summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose Bollo <jose.bollo@iot.bzh>2019-09-30 17:40:04 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2019-10-03 12:35:01 +0200
commitf161cd8b8b83a29f42c275fe31a96825a8d27d86 (patch)
treef13aaf40ea67fe0c4459a283dd0773a00752c740
parent6bf1b8c3a8af299c04d9be0d59b42c3a6d7c9127 (diff)
Improve comments
Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
-rw-r--r--src/agent-at.c51
-rw-r--r--src/agent-at.h6
-rw-r--r--src/anydb.c435
-rw-r--r--src/anydb.h213
-rw-r--r--src/cache.c113
-rw-r--r--src/cache.h43
-rw-r--r--src/cyn.c235
-rw-r--r--src/cyn.h136
-rw-r--r--src/data.h58
-rw-r--r--src/db.c76
-rw-r--r--src/db.h116
-rw-r--r--src/dbinit.c9
-rw-r--r--src/dbinit.h50
-rw-r--r--src/expire.c13
-rw-r--r--src/expire.h45
-rw-r--r--src/fbuf.c75
-rw-r--r--src/fbuf.h93
-rw-r--r--src/filedb.c412
-rw-r--r--src/filedb.h15
-rw-r--r--src/lib-compat.c6
-rw-r--r--src/main-cynadm.c5
-rw-r--r--src/main-cynarad.c5
-rw-r--r--src/memdb.c188
-rw-r--r--src/memdb.h10
-rw-r--r--src/pollitem.c33
-rw-r--r--src/pollitem.h45
-rw-r--r--src/prot.c147
-rw-r--r--src/prot.h122
-rw-r--r--src/queue.c64
-rw-r--r--src/queue.h31
-rw-r--r--src/rcyn-client.c5
-rw-r--r--src/rcyn-client.h8
-rw-r--r--src/rcyn-protocol.c33
-rw-r--r--src/rcyn-protocol.h48
-rw-r--r--src/rcyn-server.c13
-rw-r--r--src/rcyn-server.h7
-rw-r--r--src/socket.c7
-rw-r--r--src/socket.h6
38 files changed, 2196 insertions, 781 deletions
diff --git a/src/agent-at.c b/src/agent-at.c
index e646ab7..21193f1 100644
--- a/src/agent-at.c
+++ b/src/agent-at.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF AGENT AT (@) */
+/******************************************************************************/
+/******************************************************************************/
#include <stdlib.h>
#include <stdint.h>
@@ -27,19 +32,19 @@
/**
* Parse the spec to extract the derived key to ask.
*
- * @param spec The specification of the derived key
- * @param rkey The originally requested key
- * @param key The derived key or NULL for computing length
- * @param buffer The buffer that handles texts or NULL for computing length
- * @param szbuf The size of the buffer or 0 for computing length
+ * @param spec The specification of the derived key
+ * @param reference_key The originally requested key of reference
+ * @param derived_key The derived key or NULL for computing length
+ * @param buffer The buffer that handles texts or NULL for computing length
+ * @param szbuf The size of the buffer or 0 for computing length
* @return the total length of buffer used
*/
static
size_t
parse(
const char *spec,
- const data_key_t *rkey,
- data_key_t *key,
+ const data_key_t *reference_key,
+ data_key_t *derived_key,
char *buffer,
size_t szbuf
) {
@@ -47,8 +52,10 @@ parse(
const char *val;
int sub;
+ /* iterate through the fields of the key */
iout = 0;
for (ikey = 0 ; ikey < KeyIdx_Count ; ikey++) {
+ /* compute value of the derived field */
inf = iout;
while(*spec) {
if (*spec == ':' && ikey < 3) {
@@ -66,19 +73,19 @@ parse(
/* what % substitution is it? */
switch(spec[1]) {
case 'c':
- val = rkey->client;
+ val = reference_key->client;
sub = 1;
break;
case 's':
- val = rkey->session;
+ val = reference_key->session;
sub = 1;
break;
case 'u':
- val = rkey->user;
+ val = reference_key->user;
sub = 1;
break;
case 'p':
- val = rkey->permission;
+ val = reference_key->permission;
sub = 1;
break;
default:
@@ -97,7 +104,7 @@ parse(
if (iout < szbuf)
buffer[iout] = spec[1];
iout++;
- } else if (val) {
+ } else if (val != NULL) {
/* substitution of the value */
while (*val) {
if (iout < szbuf)
@@ -109,8 +116,9 @@ parse(
spec += 2;
}
}
+ /* standardize the found item*/
if (inf == iout)
- val = 0; /* empty key item */
+ val = NULL; /* empty key item */
else {
/* set zero ended key */
val = &buffer[inf];
@@ -118,8 +126,9 @@ parse(
buffer[iout] = 0;
iout++;
}
- if (key)
- key->keys[ikey] = val;
+ /* record the value */
+ if (derived_key)
+ derived_key->keys[ikey] = val;
}
return iout;
}
@@ -131,9 +140,8 @@ parse(
* @param agent_closure closure of the agent (not used)
* @param key the original searched key
* @param value the value found (string after @:)
- * @param on_result_cb callback that will asynchronously handle the result
- * @param on_result_closure closure for 'on_result_cb'
- * @return
+ * @param query the query identifer for replying or subquerying
+ * @return 0 in case of success or -errno like negative error code
*/
static
int
@@ -149,13 +157,16 @@ agent_at_cb(
size_t size;
/* compute the length */
- size = parse(value, key, 0, 0, 0);
+ size = parse(value, key, NULL, NULL, 0);
+
/* alloc the length locally */
block = alloca(size);
+
/* initialize the derived key */
parse(value, key, &atkey, block, size);
+
/* ask for the derived key */
- return cyn_subquery_async(query, (on_result_cb_t*)cyn_reply_query, query, &atkey);
+ return cyn_query_subquery_async(query, (on_result_cb_t*)cyn_query_reply, query, &atkey);
}
/* see agent-at.h */
diff --git a/src/agent-at.h b/src/agent-at.h
index 60dd168..68f1d3a 100644
--- a/src/agent-at.h
+++ b/src/agent-at.h
@@ -14,8 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF AGENT AT (@) */
+/******************************************************************************/
+/******************************************************************************/
/**
* Activate the AT-agent
diff --git a/src/anydb.c b/src/anydb.c
index d522c96..9196e5c 100644
--- a/src/anydb.c
+++ b/src/anydb.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* HIGH LEVEL ABSTRACTION OF THE DATABASES */
+/******************************************************************************/
+/******************************************************************************/
#include <stdlib.h>
#include <stdint.h>
@@ -31,13 +36,38 @@
#define USER_MATCH_SCORE 1
#define PERMISSION_MATCH_SCORE 1
+/**
+ * helper for searching items
+ */
+union searchkey {
+ struct {
+ /** client id */
+ anydb_idx_t idxcli;
+
+ /** session id */
+ anydb_idx_t idxses;
+
+ /** user id */
+ anydb_idx_t idxusr;
+
+ /** permission string */
+ const char *strperm;
+ };
+ anydb_key_t key;
+};
+typedef union searchkey searchkey_t;
+
/******************************************************************************/
/******************************************************************************/
/*** UTILITIES ***/
/******************************************************************************/
/******************************************************************************/
-/** check whether the 'text' fit String_Any, NULL or "" */
+/**
+ * Check whether the 'text' fit String_Any, NULL or ""
+ * @param text the text to check
+ * @return true if text matches ANY possible values
+ */
static
bool
is_any(
@@ -46,7 +76,11 @@ is_any(
return text == NULL || text[0] == 0 || (!text[1] && text[0] == Data_Any_Char);
}
-/** check whether the 'text' fit String_Any, String_Wide, NULL or "" */
+/**
+ * check whether the 'text' fit String_Any, String_Wide, NULL or ""
+ * @param text the text to check
+ * @return true if text matches ANY or WIDE possible values
+ */
static
bool
is_any_or_wide(
@@ -56,7 +90,12 @@ is_any_or_wide(
|| (!text[1] && (text[0] == Data_Any_Char || text[0] == Data_Wide_Char));
}
-/** return the name of 'index' */
+/**
+ * Get the name stored for index
+ * @param db the anydb database to query
+ * @param idx the index of the string to get
+ * @return the name or NULL if doesn't exist
+ */
static
const char*
string(
@@ -70,7 +109,14 @@ string(
return db->itf.string(db->clodb, idx);
}
-/** search the index of 'name' and create it if 'create' */
+/**
+ * Search the index of 'name' and create it if 'create'
+ * @param db the anydb database to query
+ * @param idx where to store the result if needed
+ * @param name name to search and/or create
+ * @param create if not nul, the name is created if it doesn't exist
+ * @return 0 in case of success of -errno
+ */
static
int
idx(
@@ -79,27 +125,39 @@ idx(
const char *name,
bool create
) {
- /* special names */
+ /* handle special names */
if (!name || !name[0]) {
+ /* no name or empty name means ANY */
*idx = AnyIdx_Any;
return 0;
}
+ /* handle special names of one character */
if (!name[1]) {
if (name[0] == Data_Any_Char) {
+ /* Single char for ANY */
*idx = AnyIdx_Any;
return 0;
}
if (name[0] == Data_Wide_Char) {
+ /* Single char for WIDE */
*idx = AnyIdx_Wide;
return 0;
}
}
- /* other case */
+ /* other case: ask the database backend */
return db->itf.index(db->clodb, idx, name, create);
}
-/** search the index of 'name' and create it if 'create' */
+/**
+ * Search the index of 'name' and create it if 'create'
+ * Return the index for WIDE if name matches ANY or WIDE
+ * @param db the backend database
+ * @param idx where to store the found index
+ * @param name the name to search or create
+ * @param create not nul for authorizing creation of the index for name
+ * @return 0 on success
+ */
static
int
idx_but_any(
@@ -117,7 +175,14 @@ idx_but_any(
return db->itf.index(db->clodb, idx, name, create);
}
-/** search the index of 'name' and create it if 'create' */
+/**
+ * Return the index of 'name' in the database 'db'. In option 'create' it.
+ * If the name encode ANY or WIDE returns WIDE.
+ * @param db the backend database
+ * @param name the name to search or create
+ * @param create not nul for authorizing creation of the index for name
+ * @return the found index or AnyIdx_None if not found.
+ */
static
anydb_idx_t
idx_or_none_but_any(
@@ -134,11 +199,124 @@ idx_or_none_but_any(
/******************************************************************************/
/******************************************************************************/
+/*** SEARCH KEYS ***/
+/******************************************************************************/
+/******************************************************************************/
+
+static
+bool
+searchkey_prepare_match(anydb_t *db,
+ const data_key_t *key,
+ searchkey_t *skey,
+ bool create
+) {
+ if (idx(db, &skey->idxcli, key->client, create)
+ || idx(db, &skey->idxses, key->session, create)
+ || idx(db, &skey->idxusr, key->user, create))
+ return false; /* one of the idx doesn't exist */
+ skey->strperm = is_any(key->permission) ? NULL : key->permission;
+
+ return true;
+}
+
+static
+bool
+searchkey_match(
+ anydb_t *db,
+ const anydb_key_t *key,
+ const searchkey_t *skey
+) {
+ return (skey->idxcli == AnyIdx_Any || skey->idxcli == key->client)
+ && (skey->idxses == AnyIdx_Any || skey->idxses == key->session)
+ && (skey->idxusr == AnyIdx_Any || skey->idxusr == key->user)
+ && (!skey->strperm || !strcasecmp(skey->strperm, string(db, key->permission)));
+}
+
+static
+int
+searchkey_prepare_is(
+ anydb_t *db,
+ const data_key_t *key,
+ searchkey_t *skey,
+ bool create
+) {
+ int rc;
+
+ rc = idx_but_any(db, &skey->idxcli, key->client, create);
+ if (!rc) {
+ rc = idx_but_any(db, &skey->idxses, key->session, create);
+ if (!rc) {
+ rc = idx_but_any(db, &skey->idxusr, key->user, create);
+ if (!rc)
+ skey->strperm = key->permission;
+ }
+ }
+ return rc;
+}
+
+static
+bool
+searchkey_is(
+ anydb_t *db,
+ const anydb_key_t *key,
+ const searchkey_t *skey
+) {
+ return skey->idxcli == key->client
+ && skey->idxses == key->session
+ && skey->idxusr == key->user
+ && !strcasecmp(skey->strperm, string(db, key->permission));
+}
+
+static
+void
+searchkey_prepare_test(
+ anydb_t *db,
+ const data_key_t *key,
+ searchkey_t *skey,
+ bool create
+) {
+ skey->idxcli = idx_or_none_but_any(db, key->client, create);
+ skey->idxses = idx_or_none_but_any(db, key->session, create);
+ skey->idxusr = idx_or_none_but_any(db, key->user, create);
+ skey->strperm = key->permission;
+}
+
+static
+unsigned
+searchkey_test(
+ anydb_t *db,
+ const anydb_key_t *key,
+ const searchkey_t *skey
+) {
+ unsigned sc;
+
+ if ((key->client != AnyIdx_Wide && skey->idxcli != key->client)
+ || (key->session != AnyIdx_Wide && skey->idxses != key->session)
+ || (key->user != AnyIdx_Wide && skey->idxusr != key->user)
+ || (key->permission != AnyIdx_Wide
+ && strcasecmp(skey->strperm, string(db, key->permission)))) {
+ sc = 0;
+ } else {
+ sc = 1;
+ if (key->client != AnyIdx_Wide)
+ sc += CLIENT_MATCH_SCORE;
+ if (key->session != AnyIdx_Wide)
+ sc += SESSION_MATCH_SCORE;
+ if (key->user != AnyIdx_Wide)
+ sc += USER_MATCH_SCORE;
+ if (key->permission != AnyIdx_Wide)
+ sc += PERMISSION_MATCH_SCORE;
+ }
+ return sc;
+}
+
+/******************************************************************************/
+/******************************************************************************/
/*** FOR ALL ***/
/******************************************************************************/
/******************************************************************************/
-/** manage atomicity of operations */
+/* see anydb.h */
int
anydb_transaction(
anydb_t *db,
@@ -157,17 +335,14 @@ anydb_transaction(
struct for_all_s
{
- anydb_t *db;
+ anydb_t *db; /* targeted database */
+ time_t now; /* also drop expired items */
+ searchkey_t skey;
void *closure;
void (*callback)(
void *closure,
const data_key_t *key,
const data_value_t *value);
- anydb_idx_t idxcli;
- anydb_idx_t idxses;
- anydb_idx_t idxusr;
- const char *strperm;
- time_t now;
};
static
@@ -181,48 +356,41 @@ for_all_cb(
data_key_t k;
data_value_t v;
+ /* drop expired items */
if (value->expire && value->expire <= s->now)
return Anydb_Action_Remove_And_Continue;
- if ((s->idxcli == AnyIdx_Any || s->idxcli == key->client)
- && (s->idxses == AnyIdx_Any || s->idxses == key->session)
- && (s->idxusr == AnyIdx_Any || s->idxusr == key->user)) {
+ if (searchkey_match(s->db, key, &s->skey)) {
+ k.client = string(s->db, key->client);
+ k.session = string(s->db, key->session);
+ k.user = string(s->db, key->user);
k.permission = string(s->db, key->permission);
- if (!s->strperm || !strcasecmp(s->strperm, k.permission)) {
- k.client = string(s->db, key->client);
- k.session = string(s->db, key->session);
- k.user = string(s->db, key->user);
- v.value = string(s->db, value->value);
- v.expire = value->expire;
- s->callback(s->closure, &k, &v);
- }
+ v.value = string(s->db, value->value);
+ v.expire = value->expire;
+ s->callback(s->closure, &k, &v);
}
return Anydb_Action_Continue;
}
-/** enumerate */
+/* see anydb.h */
void
anydb_for_all(
anydb_t *db,
- void *closure,
void (*callback)(
void *closure,
const data_key_t *key,
const data_value_t *value),
+ void *closure,
const data_key_t *key
) {
struct for_all_s s;
+ if (!searchkey_prepare_match(db, key, &s.skey, false))
+ return; /* nothing to do! because one of the idx doesn't exist */
+
s.db = db;
s.closure = closure;
s.callback = callback;
-
- if (idx(db, &s.idxcli, key->client, false)
- || idx(db, &s.idxses, key->session, false)
- || idx(db, &s.idxusr, key->user, false))
- return; /* nothing to do! because one of the idx doesn't exist */
- s.strperm = is_any(key->permission) ? NULL : key->permission;
-
s.now = time(NULL);
db->itf.apply(db->clodb, for_all_cb, &s);
}
@@ -233,16 +401,15 @@ anydb_for_all(
/******************************************************************************/
/******************************************************************************/
+/* structure for dropping items */
struct drop_s
{
- anydb_t *db;
- anydb_idx_t idxcli;
- anydb_idx_t idxses;
- anydb_idx_t idxusr;
- const char *strperm;
- time_t now;
+ anydb_t *db; /* targeted database */
+ time_t now; /* also drop expired items */
+ searchkey_t skey; /* the search key */
};
+/* callback for dropping items */
static
anydb_action_t
drop_cb(
@@ -252,57 +419,50 @@ drop_cb(
) {
struct drop_s *s = closure;
+ /* drop expired items */
if (value->expire && value->expire <= s->now)
return Anydb_Action_Remove_And_Continue;
- if ((s->idxcli == AnyIdx_Any || s->idxcli == key->client)
- && (s->idxses == AnyIdx_Any || s->idxses == key->session)
- && (s->idxusr == AnyIdx_Any || s->idxusr == key->user)
- && (!s->strperm || !strcasecmp(s->strperm, string(s->db, key->permission))))
+ /* remove if matches the key */
+ if (searchkey_match(s->db, key, &s->skey))
return Anydb_Action_Remove_And_Continue;
+ /* continue to next */
return Anydb_Action_Continue;
}
-/** drop rules */
-int
+/* see anydb.h */
+void
anydb_drop(
anydb_t *db,
const data_key_t *key
) {
struct drop_s s;
- s.db = db;
-
- if (idx(db, &s.idxcli, key->client, false)
- || idx(db, &s.idxses, key->session, false)
- || idx(db, &s.idxusr, key->user, false))
- return 0; /* nothing to do! because one of the idx doesn't exist */
- s.strperm = is_any(key->permission) ? NULL : key->permission;
+ if (!searchkey_prepare_match(db, key, &s.skey, false))
+ return; /* nothing to do! because one of the idx doesn't exist */
+ s.db = db;
s.now = time(NULL);
db->itf.apply(db->clodb, drop_cb, &s);
- return 0;
}
/******************************************************************************/
/******************************************************************************/
-/*** ADD ***/
+/*** SET ***/
/******************************************************************************/
/******************************************************************************/
+/* structure for setting values */
struct set_s
{
- anydb_t *db;
- anydb_idx_t idxcli;
- anydb_idx_t idxses;
- anydb_idx_t idxusr;
- anydb_idx_t idxval;
- time_t expire;
- const char *strperm;
- time_t now;
+ anydb_t *db; /* targeted database */
+ time_t now; /* also drop expired items */
+ searchkey_t skey; /* searching key */
+ anydb_value_t value; /* value to set */
};
+/* callback for setting values */
static
anydb_action_t
set_cb(
@@ -312,22 +472,21 @@ set_cb(
) {
struct set_s *s = closure;
+ /* drop expired items */
if (value->expire && value->expire <= s->now)
return Anydb_Action_Remove_And_Continue;
- if (s->idxcli == key->client
- && s->idxses == key->session
- && s->idxusr == key->user
- && !strcasecmp(s->strperm, string(s->db, key->permission))) {
- value->value = s->idxval;
- value->expire = s->expire;
- s->db = NULL;
+ if (searchkey_is(s->db, key, &s->skey)) {
+ value->value = s->value.value;
+ value->expire = s->value.expire;
+ s->db = NULL; /* indicates that is found */
return Anydb_Action_Update_And_Stop;
}
return Anydb_Action_Continue;
}
+/* see anydb.h */
int
anydb_set(
anydb_t *db,
@@ -336,41 +495,25 @@ anydb_set(
) {
int rc;
struct set_s s;
- anydb_key_t k;
- anydb_value_t v;
-
- s.db = db;
- s.strperm = key->permission;
- s.expire = value->expire;
- rc = idx_but_any(db, &s.idxcli, key->client, true);
- if (rc)
- goto error;
- rc = idx_but_any(db, &s.idxses, key->session, true);
- if (rc)
- goto error;
- rc = idx_but_any(db, &s.idxusr, key->user, true);
+ rc = searchkey_prepare_is(db, key, &s.skey, true);
if (rc)
goto error;
- rc = idx(db, &s.idxval, value->value, true);
+
+ rc = idx(db, &s.value.value, value->value, true);
if (rc)
goto error;
+ s.db = db;
+ s.value.expire = value->expire;
s.now = time(NULL);
db->itf.apply(db->clodb, set_cb, &s);
if (s.db) {
- if (idx(db, &k.permission, s.strperm, true))
- goto error;
- k.client = s.idxcli;
- k.user = s.idxusr;
- k.session = s.idxses;
- v.value = s.idxval;
- v.expire = s.expire;
- rc = db->itf.add(db->clodb, &k, &v);
- if (rc)
- goto error;
+ /* no item to alter so must be added */
+ rc = idx(db, &s.skey.key.permission, key->permission, true);
+ if (!rc)
+ rc = db->itf.add(db->clodb, &s.skey.key, &s.value);
}
- return 0;
error:
return rc;
}
@@ -381,19 +524,17 @@ error:
/******************************************************************************/
/******************************************************************************/
+/* structure for testing rule */
struct test_s
{
- anydb_t *db;
- anydb_idx_t idxcli;
- anydb_idx_t idxses;
- anydb_idx_t idxusr;
- const char *strperm;
- int score;
- anydb_idx_t idxval;
- time_t expire;
+ anydb_t *db; /* targeted database */
time_t now;
+ unsigned score;
+ searchkey_t skey;
+ anydb_value_t value;
};
+/* callback for testing rule */
static
anydb_action_t
test_cb(
@@ -402,35 +543,22 @@ test_cb(
anydb_value_t *value
) {
struct test_s *s = closure;
- int sc;
+ unsigned sc;
+ /* drop expired items */
if (value->expire && value->expire <= s->now)
return Anydb_Action_Remove_And_Continue;
- if ((s->idxcli == key->client || key->client == AnyIdx_Wide)
- && (s->idxses == key->session || key->session == AnyIdx_Wide)
- && (s->idxusr == key->user || key->user == AnyIdx_Wide)
- && (AnyIdx_Wide == key->permission
- || !strcasecmp(s->strperm, string(s->db, key->permission)))) {
- sc = 1;
- if (key->client != AnyIdx_Wide)
- sc += CLIENT_MATCH_SCORE;
- if (key->session != AnyIdx_Wide)
- sc += SESSION_MATCH_SCORE;
- if (key->user != AnyIdx_Wide)
- sc += USER_MATCH_SCORE;
- if (key->permission != AnyIdx_Wide)
- sc += PERMISSION_MATCH_SCORE;
- if (sc > s->score) {
- s->score = sc;
- s->idxval = value->value;
- s->expire = value->expire;
- }
+ sc = searchkey_test(s->db, key, &s->skey);
+ if (sc > s->score) {
+ s->score = sc;
+ s->value = *value;
}
return Anydb_Action_Continue;
}
-int
+/* see anydb.h */
+unsigned
anydb_test(
anydb_t *db,
const data_key_t *key,
@@ -438,34 +566,27 @@ anydb_test(
) {
struct test_s s;
+ searchkey_prepare_test(db, key, &s.skey, true);
+
s.db = db;
s.now = time(NULL);
- s.strperm = key->permission;
- s.expire = value->expire;
-
- s.idxcli = idx_or_none_but_any(db, key->client, true);
- s.idxses = idx_or_none_but_any(db, key->session, true);
- s.idxusr = idx_or_none_but_any(db, key->user, true);
-
- s.expire = -1;
- s.idxval = AnyIdx_Invalid;
s.score = 0;
-
db->itf.apply(db->clodb, test_cb, &s);
-
if (s.score) {
- value->value = string(db, s.idxval);
- value->expire = s.expire;
+ value->value = string(db, s.value.value);
+ value->expire = s.value.expire;
}
return s.score;
}
+
/******************************************************************************/
/******************************************************************************/
/*** IS EMPTY ***/
/******************************************************************************/
/******************************************************************************/
+/* callback for computing if empty */
static
anydb_action_t
is_empty_cb(
@@ -473,18 +594,23 @@ is_empty_cb(
const anydb_key_t *key,
anydb_value_t *value
) {
- bool *result = closure;
- *result = false;
+ time_t *t = closure;
+ if (value->expire && value->expire <= *t)
+ return Anydb_Action_Remove_And_Continue;
+ *t = 0;
return Anydb_Action_Stop;
}
+/* see anydb.h */
bool
anydb_is_empty(
anydb_t *db
) {
- bool result = true;
- db->itf.apply(db->clodb, is_empty_cb, &result);
- return result;
+ time_t t;
+
+ t = time(NULL);
+ db->itf.apply(db->clodb, is_empty_cb, &t);
+ return !t;
}
/******************************************************************************/
@@ -493,6 +619,7 @@ anydb_is_empty(
/******************************************************************************/
/******************************************************************************/
+/* cleanup callback */
static
anydb_action_t
cleanup_cb(
@@ -500,12 +627,11 @@ cleanup_cb(
const anydb_key_t *key,
anydb_value_t *value
) {
- if (value->expire && value->expire <= *(time_t*)closure)
- return Anydb_Action_Remove_And_Continue;
-
- return Anydb_Action_Continue;
+ return value->expire && value->expire <= *(time_t*)closure
+ ? Anydb_Action_Remove_And_Continue : Anydb_Action_Continue;
}
+/* see anydb.h */
void
anydb_cleanup(
anydb_t *db
@@ -519,10 +645,25 @@ anydb_cleanup(
/******************************************************************************/
/******************************************************************************/
+/*** SYNCHRONIZE ***/
+/******************************************************************************/
+/******************************************************************************/
+
+/* see anydb.h */
+int
+anydb_sync(
+ anydb_t *db
+) {
+ return db->itf.sync ? db->itf.sync(db->clodb) : 0;
+}
+
+/******************************************************************************/
+/******************************************************************************/
/*** DESTROY ***/
/******************************************************************************/
/******************************************************************************/
+/* see anydb.h */
void
anydb_destroy(
anydb_t *db
diff --git a/src/anydb.h b/src/anydb.h
index 843ef29..64f86bd 100644
--- a/src/anydb.h
+++ b/src/anydb.h
@@ -14,8 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* HIGH LEVEL ABSTRACTION OF THE DATABASES */
+/******************************************************************************/
+/******************************************************************************/
/**
* An index is an integer
@@ -29,10 +33,16 @@ typedef uint32_t anydb_idx_t;
/** The invalid index */
#define AnyIdx_Invalid ((anydb_idx_t)0xffffffffu)
-/** */
+/** The index for ANY */
#define AnyIdx_Any ((anydb_idx_t)0xfffffffeu)
+
+/** The index for WIDE */
#define AnyIdx_Wide ((anydb_idx_t)0xfffffffdu)
+
+/** The index for NONE */
#define AnyIdx_None ((anydb_idx_t)0xfffffffcu)
+
+/** The maximum value for indexes */
#define AnyIdx_Max ((anydb_idx_t)0xfffffff7u)
/**
@@ -67,45 +77,155 @@ struct anydb_value
typedef struct anydb_value anydb_value_t;
/**
+ * Operation of the transaction
*/
-enum anydb_action
-{
- Anydb_Action_Stop,
- Anydb_Action_Continue,
- Anydb_Action_Update_And_Stop,
- Anydb_Action_Remove_And_Continue
-};
-typedef enum anydb_action anydb_action_t;
-
enum anydb_transaction
{
+ /**
+ * Operation: Start a cancelable transaction
+ */
Anydb_Transaction_Start = 0,
+
+ /**
+ * Operation: Terminate the started transaction and commit its changes
+ */
Anydb_Transaction_Commit = 1,
+
+ /**
+ * Operation: Terminate the started transaction and cancel its changes
+ */
Anydb_Transaction_Cancel = 2
};
typedef enum anydb_transaction anydb_transaction_t;
+/**
+ * Actions to perform in response to anydb_applycb_t callbacks.
+ */
+enum anydb_action
+{
+ /** Continue to apply with the next element of the database */
+ Anydb_Action_Continue = 0,
+
+ /** Stop to apply */
+ Anydb_Action_Stop = 1,
+
+ /** Update the current element (implicitly, also continue) */
+ Anydb_Action_Update = 2,
+
+ /** Remove the current element (implicitly, also continue) */
+ Anydb_Action_Remove = 4,
+
+ /** Update the current element and stop to apply */
+ Anydb_Action_Update_And_Stop = Anydb_Action_Update | Anydb_Action_Stop,
+
+ /** Update the current element and continue to apply */
+ Anydb_Action_Update_And_Continue = Anydb_Action_Update | Anydb_Action_Continue,
+
+ /** Remove the current element and stop to apply */
+ Anydb_Action_Remove_And_Stop = Anydb_Action_Remove | Anydb_Action_Stop,
+
+ /** Remove the current element and continue to apply */
+ Anydb_Action_Remove_And_Continue = Anydb_Action_Remove | Anydb_Action_Continue
+};
+typedef enum anydb_action anydb_action_t;
+
+/**
+ * Callback of apply method. This callback is called for any item of
+ * the database and it tells through its return what the anydb has
+ * to do: see anydb_action_t.
+ * The 'closure' is the closure given by the caller of 'apply' method.
+ * 'key' is the iterated key of the anydb. It can not be changed.
+ * 'value' is the value stored in the database for the key.
+ */
+typedef anydb_action_t anydb_applycb_t(void *closure, const anydb_key_t *key, anydb_value_t *value);
+
+/**
+ * Interface to any database implementation
+ */
struct anydb_itf
{
+ /**
+ * Get the index of the 'name' in 'idx'. If the name is found
+ * then its index is returned. If the name is not found, the
+ * database backend has to create it if 'create' is not zero.
+ * 'clodb' is the database's closure.
+ * Returns 0 in case of success (*idx filled with the index)
+ * or return a negative error code in -errno like form.
+ */
int (*index)(void *clodb, anydb_idx_t *idx, const char *name, bool create);
+
+ /**
+ * Get the string for the index 'idx'. idx MUST be valid.
+ * 'clodb' is the database's closure.
+ */
const char *(*string)(void *clodb, anydb_idx_t idx);
+
+ /**
+ * Start, Commit or Cancel a cancellable transaction. The operation
+ * to perform is given by 'op'.
+ * 'clodb' is the database's closure.
+ * Returns 0 in case of success or return a negative error code
+ * in -errno like form.
+ */
int (*transaction)(void *clodb, anydb_transaction_t atomic_op);
- void (*apply)(void *clodb, anydb_action_t (*oper)(void *closure, const anydb_key_t *key, anydb_value_t *value), void *closure);
+
+ /**
+ * Iterate over the database items and apply the operator 'oper'.
+ * The callback operator 'oper' is called with the given 'closure'
+ * and the key and value for the item. It can modify or delete the item.
+ * 'clodb' is the database's closure.
+ */
+ void (*apply)(void *clodb, anydb_applycb_t *oper, void *closure);
+
+ /**
+ * Add the item of 'key' and 'value'.
+ * 'clodb' is the database's closure.
+ * Returns 0 in case of success or return a negative error code
+ * in -errno like form.
+ */
int (*add)(void *clodb, const anydb_key_t *key, const anydb_value_t *value);
+
+ /**
+ * Garbage collection of unused items.
+ * 'clodb' is the database's closure.
+ */
void (*gc)(void *clodb);
+
+ /**
+ * Synchronize the database and its longterm support (file)
+ * 'clodb' is the database's closure.
+ * Returns 0 in case of success or return a negative error code
+ * in -errno like form.
+ */
int (*sync)(void *clodb);
+
+ /**
+ * Destroys the database
+ * 'clodb' is the database's closure.
+ */
void (*destroy)(void *clodb);
};
typedef struct anydb_itf anydb_itf_t;
+/**
+ * The structure for abstracting backend databases
+ */
struct anydb
{
+ /** the closure */
void *clodb;
+
+ /** the implementation methods */
anydb_itf_t itf;
};
typedef struct anydb anydb_t;
-/** manage atomicity of operations */
+/**
+ * Manage atomicity of modifications by enabling cancellation
+ * @param db database to manage
+ * @param oper operation to perform
+ * @return 0 in case of success or a negative error code in -errno like form.
+ */
extern
int
anydb_transaction(
@@ -113,28 +233,44 @@ anydb_transaction(
anydb_transaction_t oper
);
-/** enumerate */
+/**
+ * Enumerate items of the database matching the given key
+ * @param db database to enumerate
+ * @param callback callback function receiving the item that matches the key
+ * @param closure closure for the callback
+ * @param key key to restrict enumeration can't be NULL
+ */
extern
void
anydb_for_all(
anydb_t *db,
- void *closure,
void (*callback)(
void *closure,
const data_key_t *key,
const data_value_t *value),
+ void *closure,
const data_key_t *key
);
-/** drop rules */
+/**
+ * Drop any rule that matches the key
+ * @param db database to modify
+ * @param key the key that select items to be dropped
+ */
extern
-int
+void
anydb_drop(
anydb_t *db,
const data_key_t *key
);
-/** set a rules */
+/**
+ * Set the rule described by key and value
+ * @param db the database to set
+ * @param key the key of the rule
+ * @param value the value of the rule
+ * @return 0 on success or a negative error code
+ */
extern
int
anydb_set(
@@ -143,39 +279,60 @@ anydb_set(
const data_value_t *value
);
-/** test a rule, returns 0 or the score: count of exact keys */
+/**
+ * Test a rule and return its score and the value
+ * @param db the database
+ * @param key key to be matched by rules
+ * @param value value found for the key, filled only if a key matched
+ * @return 0 if no rule matched or a positive integer when the rule matched
+ * The higher the integer is, the more accurate is the rule found.
+ */
extern
-int
+unsigned
anydb_test(
anydb_t *db,
const data_key_t *key,
data_value_t *value
);
-/** drop rules */
+/**
+ * Drop any expired rule
+ * @param db the database to clean
+ */
extern
void
anydb_cleanup(
anydb_t *db
);
-/** is the database empty? */
+/**
+ * Is the database empty?
+ * @param db the database to test
+ * @return true if the database is empty or otherwise false
+ */
extern
bool
anydb_is_empty(
anydb_t *db
);
-/** destroy the database */
+/**
+ * Synchronize the database if needed
+ * @param db the database to
+ * @return 0 on success or a negative -errno like code
+ */
extern
-void
-anydb_destroy(
+int
+anydb_sync(
anydb_t *db
);
-/** synchronize database */
+/**
+ * Destroy the database
+ * @param db the database to destroy
+ */
extern
-int
-anydb_sync(
+void
+anydb_destroy(
anydb_t *db
);
diff --git a/src/cache.c b/src/cache.c
index ca4234a..bed0b49 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -14,7 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF CACHE IN CLIENTS */
+/******************************************************************************/
+/******************************************************************************/
#include <stdlib.h>
#include <stdbool.h>
@@ -64,12 +68,25 @@ typedef struct item item_t;
*/
struct cache
{
+ /** used for clearing */
uint32_t cacheid;
+
+ /** count of bytes used */
uint32_t used;
+
+ /** count of bytes allocated */
uint32_t count;
+
+ /** content of the cache */
uint8_t content[];
};
+/**
+ * return the item at a given position
+ * @param cache the cache
+ * @param pos the position of the item
+ * @return the item
+ */
static
inline
item_t *
@@ -80,6 +97,11 @@ itemat(
return (item_t*)(&cache->content[pos]);
}
+/**
+ * Removes the item at position pos
+ * @param cache the cache
+ * @param pos the position of the item to remove
+ */
static
void
drop_at(
@@ -95,6 +117,10 @@ drop_at(
memmove(&cache->content[pos], &cache->content[e], cache->used - pos);
}
+/**
+ * Removes the oldest hit target
+ * @param cache the cache
+ */
static
void
drop_lre(
@@ -117,6 +143,11 @@ drop_lre(
drop_at(cache, found);
}
+/**
+ * tells the target is used
+ * @param cache the cache
+ * @param target the target to hit
+ */
static
void
hit(
@@ -141,34 +172,55 @@ hit(
}
}
+/**
+ * Compare the head with a string and either return NULL if it doesn't match or
+ * otherwise return the pointer to the next string for heading.
+ * @param head head of scan
+ * @param other string to compare
+ * @return NULL if no match or pointer to the strings that follows head if match
+ */
static
const char*
-cmpi(
+cmp(
const char *head,
const char *other
) {
char c;
- while(toupper(c = *head++) == toupper(*other++))
+ while((c = *head++) == *other++)
if (!c)
return head;
- return 0;
+ return NULL;
}
+/**
+ * Compare in a case independant method the head with a string and either
+ * return NULL if it doesn't match or otherwise return the pointer to the
+ * next string for heading.
+ * @param head head of scan
+ * @param other string to compare
+ * @return NULL if no match or pointer to the strings that follows head if match
+ */
static
const char*
-cmp(
+cmpi(
const char *head,
const char *other
) {
char c;
- while((c = *head++) == *other++)
+ while(toupper(c = *head++) == toupper(*other++))
if (!c)
return head;
return 0;
}
+/**
+ * Check if a head of strings matche the key
+ * @param head the head of strings
+ * @param key the key
+ * @return true if matches or false other wise
+ */
static
-int
+bool
match(
const char *head,
const rcyn_key_t *key
@@ -181,13 +233,19 @@ match(
if (head) {
head = cmpi(head, key->permission);
if (head)
- return 1;
+ return true;
}
}
}
- return 0;
+ return false;
}
+/**
+ * Search the item matching key and return it. Also remove expired entries
+ * @param cache the cache
+ * @param key the key to search
+ * @return the found item or NULL if not found
+ */
static
item_t*
search(
@@ -214,6 +272,7 @@ search(
return found;
}
+/* see cache.h */
int
cache_put(
cache_t *cache,
@@ -255,6 +314,7 @@ cache_put(
return 0;
}
+/* see cache.h */
int
cache_search(
cache_t *cache,
@@ -272,6 +332,7 @@ cache_search(
return -ENOENT;
}
+/* see cache.h */
void
cache_clear(
cache_t *cache,
@@ -283,35 +344,43 @@ cache_clear(
}
}
+/* see cache.h */
int
cache_resize(
cache_t **cache,
uint32_t newsize
) {
- cache_t *c = *cache, *nc;
+ cache_t *oldcache = *cache, *newcache;
if (newsize == 0) {
- free(c);
- nc = NULL;
+ /* erase all */
+ free(oldcache);
+ newcache = NULL;
} else {
- if (c)
- while (c->used > newsize)
- drop_lre(c);
+ /* coerce cache values if downsizing */
+ if (oldcache) {
+ while (oldcache->used > newsize)
+ drop_lre(oldcache);
+ }
- nc = realloc(c, newsize + sizeof *c);
- if (nc == NULL)
+ /* reallocate the cache */
+ newcache = realloc(oldcache, newsize + sizeof *oldcache);
+ if (newcache == NULL)
return -ENOMEM;
- nc->count = newsize;
- if (!c) {
- nc->cacheid = 0;
- nc->used = 0;
+ /* init */
+ newcache->count = newsize;
+ if (!oldcache) {
+ newcache->cacheid = 0;
+ newcache->used = 0;
}
}
- *cache = nc;
+ /* update cache */
+ *cache = newcache;
return 0;
}
+/* see cache.h */
int
cache_create(
cache_t **cache,
diff --git a/src/cache.h b/src/cache.h
index dd37d92..d694e9b 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -14,12 +14,22 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF CACHE IN CLIENTS */
+/******************************************************************************/
+/******************************************************************************/
-struct cache;
+/** opaque structure for cache */
typedef struct cache cache_t;
+/**
+ * Search the stored value for the key
+ * @param cache the cache handler
+ * @param key the key to search
+ * @return the stored value or -ENOENT if not found
+ */
extern
int
cache_search(
@@ -27,6 +37,16 @@ cache_search(
const rcyn_key_t *key
);
+/**
+ * Add the value for the key in the cache
+ * @param cache the cache handler
+ * @param key the key to cache
+ * @param value the value (must be an integer from -128 to 127)
+ * @param expire expiration date
+ * @return 0 on success
+ * -EINVAL invalid argument
+ * -ENOMEM too big for the cache size
+ */
extern
int
cache_put(
@@ -36,6 +56,11 @@ cache_put(
time_t expire
);
+/**
+ * Clear the content of the cache if the cacheid doesn't match the current one
+ * @param cache the cache handler
+ * @param cacheid the cacheid to set or zero to force clearing
+ */
extern
void
cache_clear(
@@ -43,6 +68,13 @@ cache_clear(
uint32_t cacheid
);
+/**
+ *
+ * @param cache pointer to the cache handler
+ * @param newsize new size to set to the cache
+ * @return 0 on success
+ * -ENOMEM not enough memory
+ */
extern
int
cache_resize(
@@ -50,6 +82,13 @@ cache_resize(
uint32_t newsize
);
+/**
+ *
+ * @param cache pointer to the cache handler
+ * @param size size to set to the cache
+ * @return 0 on success
+ * -ENOMEM not enough memory
+ */
extern
int
cache_create(
diff --git a/src/cyn.c b/src/cyn.c
index 6978251..f82e3cd 100644
--- a/src/cyn.c
+++ b/src/cyn.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF LOCAL CYNARA API */
+/******************************************************************************/
+/******************************************************************************/
#include <assert.h>
#include <stdlib.h>
@@ -31,6 +36,9 @@
#if !CYN_SEARCH_DEEP_MAX
# define CYN_SEARCH_DEEP_MAX 10
#endif
+#if !defined(AGENT_SEPARATOR_CHARACTER)
+# define AGENT_SEPARATOR_CHARACTER ':'
+#endif
/**
* items of the list of observers or awaiters
@@ -39,14 +47,19 @@ struct callback
{
/** link to the next item of the list */
struct callback *next;
+
+ /** recording of callback function */
union {
/** any callback value */
void *any_cb;
+
/** awaiter callback */
on_enter_cb_t *on_enter_cb;
+
/** observer callback */
on_change_cb_t *on_change_cb;
};
+
/** closure of the callback */
void *closure;
};
@@ -65,7 +78,7 @@ struct agent
/** closure of the callback */
void *closure;
- /** length of the name */
+ /** length of the name (without terminating zero) */
uint8_t len;
/** name of the agent */
@@ -73,7 +86,7 @@ struct agent
};
/**
- * structure handling an asynchronous check
+ * structure handling an asynchronous requests
*/
struct cyn_query
{
@@ -86,15 +99,12 @@ struct cyn_query
/** key of the check */
data_key_t key;
- /** value of the check */
- data_value_t value;
-
/** down counter for recursivity limitation */
int decount;
};
-/** locking critical section */
-static const void *lock;
+/** for locking critical section with magic */
+static const void *magic_locker;
/** head of the list of critical section awaiters */
static struct callback *awaiters;
@@ -102,17 +112,24 @@ static struct callback *awaiters;
/** head of the list of change observers */
static struct callback *observers;
-/** head of the list of agents */
+/** head of the list of recorded agents */
static struct agent *agents;
-/** last changeid */
-static uint32_t last_changeid;
+/** holding of changeid */
+static struct {
+ /** current changeid */
+ uint32_t current;
-/** changeid of the current 'changeid_string' */
-static uint32_t last_changeid_string;
+ /** changeid set in string */
+ uint32_t instring;
-/** string buffer for changeid */
-static char changeid_string[12];
+ /** string value for a changeid */
+ char string[12];
+} changeid = {
+ .current = 1,
+ .instring = 0,
+ .string = { 0 }
+};
/**
* Delete from the list represented by 'head' the entry for
@@ -179,7 +196,7 @@ changed(
) {
struct callback *c;
- ++last_changeid;
+ changeid.current = changeid.current + 1 ?: 1;
for (c = observers; c ; c = c->next)
c->on_change_cb(c->closure);
}
@@ -191,9 +208,9 @@ cyn_enter(
) {
if (!magic)
return -EINVAL;
- if (lock)
+ if (magic_locker)
return -EBUSY;
- lock = magic;
+ magic_locker = magic;
return 0;
}
@@ -205,10 +222,10 @@ cyn_enter_async(
) {
if (!magic)
return -EINVAL;
- if (lock)
+ if (magic_locker)
return addcb(enter_cb, magic, &awaiters);
- lock = magic;
+ magic_locker = magic;
enter_cb(magic);
return 0;
}
@@ -251,12 +268,12 @@ cyn_leave(
if (!magic)
return -EINVAL;
- if (!lock)
+ if (!magic_locker)
return -EALREADY;
- if (lock != magic)
+ if (magic_locker != magic)
return -EPERM;
- lock = &lock;
+ magic_locker = &magic_locker;
if (!commit)
rc = 0;
else {
@@ -273,7 +290,7 @@ cyn_leave(
/* wake up awaiting client */
e = awaiters;
if (!e)
- lock = 0;
+ magic_locker = 0;
else {
/* the one to awake is at the end of the list */
p = &awaiters;
@@ -282,7 +299,7 @@ cyn_leave(
e = *p;
}
*p = NULL;
- lock = e->closure;
+ magic_locker = e->closure;
e->on_enter_cb(e->closure);
free(e);
}
@@ -296,7 +313,7 @@ cyn_set(
const data_key_t *key,
const data_value_t *value
) {
- if (!lock)
+ if (!magic_locker)
return -EPERM;
return queue_set(key, value);
}
@@ -306,7 +323,7 @@ int
cyn_drop(
const data_key_t *key
) {
- if (!lock)
+ if (!magic_locker)
return -EPERM;
return queue_drop(key);
}
@@ -314,15 +331,16 @@ cyn_drop(
/* see cyn.h */
void
cyn_list(
- void *closure,
list_cb_t *callback,
+ void *closure,
const data_key_t *key
) {
- db_for_all(closure, callback, key);
+ db_for_all(callback, closure, key);
}
/**
* initialize value to its default
+ *
* @param value to initialize
* @return the initialized value
*/
@@ -338,8 +356,9 @@ default_value(
/**
* Search the agent of name and return its item in the list
+ *
* @param name of the agent to find (optionally zero terminated)
- * @param len length of the name
+ * @param len length of the name (without terminating zero)
* @param ppprev for catching the pointer referencing the return item
* @return 0 if not found or the pointer to the item of the found agent
*/
@@ -347,56 +366,51 @@ static
struct agent *
search_agent(
const char *name,
- uint8_t len,
+ size_t length,
struct agent ***ppprev
) {
struct agent *it, **pprev;
pprev = &agents;
while((it = *pprev)
- && (len != it->len || memcmp(it->name, name, (size_t)len)))
+ && ((uint8_t)length != it->len || memcmp(it->name, name, length)))
pprev = &it->next;
*ppprev = pprev;
return it;
}
/**
- * Return the agent required by the value or 0 if no agent is required
+ * Return the agent required by the value or NULL if no agent is required
* or if the agent is not found.
+ *
* @param value string where agent is the prefix followed by one colon
- * @return the item of the required agent or 0 when no agent is required
+ * @return the item of the required agent or NULL when no agent is required
*/
static
-struct agent *
+struct agent*
required_agent(
const char *value
) {
struct agent **pprev;
- uint8_t len;
-
- for (len = 0 ; len < UINT8_MAX && value[len] ; len++)
- if (value[len] == ':')
- return search_agent(value, len, &pprev);
- return 0;
-}
+ size_t length;
-static
-void
-async_call_agent(
- struct agent *agent,
- cyn_query_t *query,
- const data_value_t *value
-) {
- int rc = agent->agent_cb(
- agent->name,
- agent->closure,
- &query->key,
- &value->value[agent->len + 1],
- query);
- if (rc < 0)
- cyn_reply_query(query, value);
+ for (length = 0 ; length <= UINT8_MAX && value[length] ; length++)
+ if (value[length] == AGENT_SEPARATOR_CHARACTER)
+ return search_agent(value, length, &pprev);
+ return NULL;
}
+/**
+ * Allocates the query structure for handling the given parameters
+ * and return it. The query structure copies the key data to be compatible
+ * with asynchronous processing.
+ *
+ * @param on_result_cb the result callback to record
+ * @param closure the closure for the result callback
+ * @param key the key of the query
+ * @param maxdepth maximum depth of the agent subrequests
+ * @return the allocated structure or NULL in case of memory depletion
+ */
static
cyn_query_t *
alloc_query(
@@ -420,6 +434,9 @@ alloc_query(
ptr = &query[1];
query->on_result_cb = on_result_cb;
query->closure = closure;
+ query->decount = maxdepth;
+
+ /* copy strings of the key */
if (!key->client)
query->key.client = 0;
else {
@@ -442,19 +459,13 @@ alloc_query(
query->key.permission = 0;
else {
query->key.permission = ptr;
- ptr = mempcpy(ptr, key->permission, szper);
+ mempcpy(ptr, key->permission, szper);
}
- query->decount = maxdepth;
}
return query;
}
-
-
-
-
-
-
+/* see cyn.h */
int
cyn_query_async(
on_result_cb_t *on_result_cb,
@@ -463,25 +474,26 @@ cyn_query_async(
int maxdepth
) {
int rc;
+ unsigned score;
data_value_t value;
cyn_query_t *query;
struct agent *agent;
/* get the direct value */
- rc = db_test(key, &value);
+ score = db_test(key, &value);
- /* on error or missing result */
- if (rc <= 0) {
+ /* missing value */
+ if (score == 0) {
default_value(&value);
on_result_cb(closure, &value);
- return rc;
+ return 0;
}
/* if not an agent or agent not required */
agent = required_agent(value.value);
if (!agent || maxdepth <= 0) {
on_result_cb(closure, &value);
- return rc;
+ return 0;
}
/* allocate asynchronous query */
@@ -492,8 +504,15 @@ cyn_query_async(
}
/* call the agent */
- async_call_agent(agent, query, &value);
- return 0;
+ rc = agent->agent_cb(
+ agent->name,
+ agent->closure,
+ &query->key,
+ &value.value[agent->len + 1],
+ query);
+ if (rc < 0)
+ cyn_query_reply(query, &value);
+ return rc;
}
/* see cyn.h */
@@ -516,8 +535,9 @@ cyn_check_async(
return cyn_query_async(on_result_cb, closure, key, CYN_SEARCH_DEEP_MAX);
}
+/* see cyn.h */
int
-cyn_subquery_async(
+cyn_query_subquery_async(
cyn_query_t *query,
on_result_cb_t *on_result_cb,
void *closure,
@@ -526,8 +546,9 @@ cyn_subquery_async(
return cyn_query_async(on_result_cb, closure, key, query->decount - 1);
}
+/* see cyn.h */
void
-cyn_reply_query(
+cyn_query_reply(
cyn_query_t *query,
const data_value_t *value
) {
@@ -535,9 +556,28 @@ cyn_reply_query(
free(query);
}
-
-
-
+/**
+ * Check the name and compute its length. Returns 0 in case of invalid name
+ * @param name the name to check
+ * @return the length of the name or zero if invalid
+ */
+static
+size_t
+check_agent_name(
+ const char *name
+) {
+ size_t length = 0;
+ if (name) {
+ while (name[length]) {
+ if (length > UINT8_MAX || name[length] == AGENT_SEPARATOR_CHARACTER) {
+ length = 0;
+ break;
+ }
+ length++;
+ }
+ }
+ return length;
+}
/* see cyn.h */
int
@@ -548,26 +588,28 @@ cyn_agent_add(
) {
struct agent *agent, **pprev;
size_t length;
- uint8_t len;
- length = strlen(name);
- if (length <= 0 || length > UINT8_MAX)
+ /* compute and check name length */
+ length = check_agent_name(name);
+ if (!length)
return -EINVAL;
- len = (uint8_t)length++;
- agent = search_agent(name, len, &pprev);
+ /* search the agent */
+ agent = search_agent(name, length, &pprev);
if (agent)
return -EEXIST;
- agent = malloc(sizeof *agent + length);
+ /* allocates the memory */
+ agent = malloc(sizeof *agent + 1 + length);
if (!agent)
return -ENOMEM;
+ /* initialize the agent */
agent->next = 0;
agent->agent_cb = agent_cb;
agent->closure = closure;
- agent->len = len;
- memcpy(agent->name, name, length);
+ agent->len = (uint8_t)length;
+ memcpy(agent->name, name, length + 1);
*pprev = agent;
return 0;
@@ -580,17 +622,18 @@ cyn_agent_remove(
) {
struct agent *agent, **pprev;
size_t length;
- uint8_t len;
- length = strlen(name);
- if (length <= 0 || length > UINT8_MAX)
+ /* compute and check name length */
+ length = check_agent_name(name);
+ if (!length)
return -EINVAL;
- len = (uint8_t)length;
- agent = search_agent(name, len, &pprev);
+ /* search the agent */
+ agent = search_agent(name, length, &pprev);
if (!agent)
return -ENOENT;
+ /* remove the found agent */
*pprev = agent->next;
free(agent);
return 0;
@@ -600,14 +643,15 @@ cyn_agent_remove(
void
cyn_changeid_reset(
) {
- last_changeid = 1;
+ changeid.current = 1;
+ changeid.instring = 0;
}
/* see cyn.h */
uint32_t
cyn_changeid(
) {
- return last_changeid;
+ return changeid.current;
}
/* see cyn.h */
@@ -615,9 +659,10 @@ const char *
cyn_changeid_string(
) {
/* regenerate the string on need */
- if (last_changeid != last_changeid_string) {
- last_changeid_string = last_changeid;
- snprintf(changeid_string, sizeof changeid_string, "%u", last_changeid);
+ if (changeid.current != changeid.instring) {
+ changeid.instring = changeid.current;
+ snprintf(changeid.string, sizeof changeid.string, "%u", changeid.current);
}
- return changeid_string;
+ /* return the string */
+ return changeid.string;
}
diff --git a/src/cyn.h b/src/cyn.h
index 5772608..fa361f6 100644
--- a/src/cyn.h
+++ b/src/cyn.h
@@ -14,11 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF LOCAL CYNARA API */
+/******************************************************************************/
+/******************************************************************************/
-#define CYN_VERSION 99
+#define CYN_VERSION 100
/**
* Callback for entering asynchronousely the critical section
@@ -120,7 +123,7 @@ cyn_leave(
* -ENOMEM critical section already locked but request can't be queued
* -EINVAL magic == NULL
*
- * @see cyn_leave, cyn_enter
+ * @see cyn_leave, cyn_enter, cyn_enter_async_cancel
*/
extern
int
@@ -131,9 +134,12 @@ cyn_enter_async(
/**
* Cancel a an asynchonous waiter to enter
+ *
* @param enter_cb the enter callback of the waiter
* @param magic the closure of the waiter
* @return 0 if entry found and removed, -ENOENT if not found
+ *
+ * @see cyn_enter_async
*/
extern
int
@@ -149,6 +155,8 @@ cyn_enter_async_cancel(
* @param closure closure of the callback
* @return 0 success
* -ENOMEM can't queue the observer
+ *
+ * @see cyn_on_change_remove
*/
extern
int
@@ -159,9 +167,12 @@ cyn_on_change_add(
/**
* Removes an on change observer
+ *
* @param on_change_cb the callback of the observer
* @param closure the closure of the observer
* @return 0 if entry found and removed, -ENOENT if not found
+ *
+ * @see cyn_on_change_add
*/
extern
int
@@ -172,6 +183,7 @@ cyn_on_change_remove(
/**
* Set or add the rule key/value to the change list to commit
+ *
* @param key the key of the rule
* @param value the value of the rule for the key
* @return 0 on success
@@ -187,6 +199,7 @@ cyn_set(
/**
* Drop any rule matching the key
+ *
* @param key the key of the rule
* @return 0 on success
* -EPERM if not locked in critical recoverable section
@@ -198,14 +211,37 @@ cyn_drop(
const data_key_t *key
);
+/**
+ * Enumerate all items matching the key
+ *
+ * @param callback callback function called for each found item
+ * @param closure the closure to the callback
+ * @param key the key to select items
+ */
extern
void
cyn_list(
- void *closure,
list_cb_t *callback,
+ void *closure,
const data_key_t *key
);
+/**
+ * Query the value for the given key.
+ *
+ * Note that the callback can be called during the call to that function.
+ *
+ * Note also that the callback will always be called either before the
+ * function returns or else later.
+ *
+ * @param on_result_cb callback function receiving the result
+ * @param closure closure for the callback
+ * @param key key to be queried
+ * @param maxdepth maximum imbrication of agent resolution
+ * @return 0 if there was no error or return the error code
+ *
+ * @see cyn_test_async, cyn_check_async
+ */
extern
int
cyn_query_async(
@@ -215,6 +251,21 @@ cyn_query_async(
int maxdepth
);
+/**
+ * Same as cyn_query_async but with a maxdepth of 0
+ *
+ * Note that the callback can be called during the call to that function.
+ *
+ * Note also that the callback will always be called either before the
+ * function returns or else later.
+ *
+ * @param on_result_cb callback function receiving the result
+ * @param closure closure for the callback
+ * @param key key to be queried
+ * @return
+ *
+ * @see cyn_query_async, cyn_check_async
+ */
extern
int
cyn_test_async(
@@ -223,6 +274,21 @@ cyn_test_async(
const data_key_t *key
);
+/**
+ * Same as cyn_query_async but with a default maxdepth for agent subqueries
+ *
+ * Note that the callback can be called during the call to that function.
+ *
+ * Note also that the callback will always be called either before the
+ * function returns or else later.
+ *
+ * @param on_result_cb callback function receiving the result
+ * @param closure closure for the callback
+ * @param key key to be queried
+ * @return 0 or -ENOMEM if some error occured
+ *
+ * @see cyn_query_async, cyn_test_async
+ */
extern
int
cyn_check_async(
@@ -231,22 +297,53 @@ cyn_check_async(
const data_key_t *key
);
+/**
+ * Makes a recursive query asynchronous
+ *
+ * Note that the callback can be called during the call to that function.
+ *
+ * Note also that the callback will always be called either before the
+ * function returns or else later.
+ *
+ * @param query the query
+ * @param on_result_cb callback function receiving the result
+ * @param closure closure for the callback
+ * @param key key to be queried
+ * @return
+ */
extern
int
-cyn_subquery_async(
+cyn_query_subquery_async(
cyn_query_t *query,
on_result_cb_t *on_result_cb,
void *closure,
const data_key_t *key
);
+/**
+ * Send the reply to a query
+ *
+ * @param query the query to reply
+ * @param value the reply value
+ */
extern
void
-cyn_reply_query(
+cyn_query_reply(
cyn_query_t *query,
const data_value_t *value
);
+/**
+ * Add the agent of name
+ *
+ * @param name name of the agent to add
+ * @param agent_cb callback of the agent
+ * @param closure closure of the callback of the agent
+ * @return 0 in case of success
+ * -EINVAL if the name is too long
+ * -EEXIST if an agent of the same name is already recorded
+ * -ENOMEM if out of memory
+ */
extern
int
cyn_agent_add(
@@ -255,22 +352,47 @@ cyn_agent_add(
void *closure
);
+/**
+ * Remove the agent of 'name'
+ *
+ * @param name name of the agent to remove
+ * @return 0 in case of successful removal
+ * -EINVAL if the name is too long
+ * -ENOENT if the agent isn't recorded
+ */
extern
int
cyn_agent_remove(
const char *name
);
+/**
+ * Reset the changeid
+ *
+ * @see cyn_changeid, cyn_changeid_string
+ */
extern
void
cyn_changeid_reset(
);
+/**
+ * Get the current changeid
+ * @return the current changeid
+ *
+ * @see cyn_changeid_rest, cyn_changeid_string
+ */
extern
uint32_t
cyn_changeid(
);
+/**
+ * Get the current changeid as a string
+ * @return the string of the current change id
+ *
+ * @see cyn_changeid_rest, cyn_changeid
+ */
extern
const char *
cyn_changeid_string(
diff --git a/src/data.h b/src/data.h
index 0e1a3b0..3c87ac3 100644
--- a/src/data.h
+++ b/src/data.h
@@ -14,24 +14,44 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* GENERIC COMMON DATA TYPES FOR CLIENTS */
+/******************************************************************************/
+/******************************************************************************/
+
+/** Maximum length of any string */
+#define MAX_NAME_LENGTH 8000
+/** string for deniying access */
#define DENY "no"
+
+/** string for allowing access */
#define ALLOW "yes"
-#define ASK "ask"
+
+/** default is denying */
#define DEFAULT DENY
+/**
+ * ANY string, made of one single character, is used to match
+ * rules and keys that can contain WIDE or other value.
+ * This allow to search specifically to WIDE when WIDE is specified in the
+ * search key or to any value (including WIDE) when any is used.
+ */
#define Data_Any_Char '#'
-#define Data_Wide_Char '*'
-
#define Data_Any_String "#"
-#define Data_Wide_String "*"
-typedef enum data_keyidx data_keyidx_t;
-typedef union data_key data_key_t;
-typedef struct data_value data_value_t;
+/**
+ * WIDE string, made of one character, is used in rules to match any
+ * queried value.
+ */
+#define Data_Wide_Char '*'
+#define Data_Wide_String "*"
+/**
+ * Name of the index on keys
+ */
enum data_keyidx {
KeyIdx_Client,
KeyIdx_Session,
@@ -39,21 +59,39 @@ enum data_keyidx {
KeyIdx_Permission,
KeyIdx_Count
};
+typedef enum data_keyidx data_keyidx_t;
+/**
+ * A key is made of 4 strings that can be accessed by index or by name
+ */
union data_key {
/* name access */
struct {
+ /** the client */
const char *client;
+
+ /** the session */
const char *session;
+
+ /** the user */
const char *user;
+
+ /** the permission */
const char *permission;
};
- /* arrayed access, see data_keyidx_t */
+ /** Array for index access, see data_keyidx_t */
const char *keys[KeyIdx_Count];
};
+typedef union data_key data_key_t;
+/**
+ * A value is made of a string (mainly ALLOW or DENY) and an expiration.
+ */
struct data_value {
+ /** judgment of the rule: ALLOW, DENY or agent description */
const char *value;
+
+ /** expiration time of the rule */
time_t expire;
};
-
+typedef struct data_value data_value_t;
diff --git a/src/db.c b/src/db.c
index aebead2..09151a1 100644
--- a/src/db.c
+++ b/src/db.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* INTERNAL DATABASE IMPLEMENTATION */
+/******************************************************************************/
+/******************************************************************************/
#include <assert.h>
#include <stdlib.h>
@@ -34,8 +39,13 @@
static anydb_t *memdb;
static anydb_t *filedb;
+static bool modifiable;
-/** check whether the 'text' fit String_Any, String_Wide, NULL or "" */
+/**
+ * check whether the 'text' fit String_Any, String_Wide, NULL or ""
+ * @param text the text to check
+ * @return true if ANY or WIDE
+ */
static
bool
is_any_or_wide(
@@ -46,7 +56,7 @@ is_any_or_wide(
}
-/** open the database for files 'names' and 'rules' (can be NULL) */
+/* see db.h */
int
db_open(
const char *directory
@@ -62,7 +72,7 @@ db_open(
return rc;
}
-/** close the database */
+/* see db.h */
void
db_close(
) {
@@ -70,32 +80,41 @@ db_close(
anydb_destroy(memdb);
}
-/** is the database empty */
+/* see db.h */
bool
db_is_empty(
) {
return anydb_is_empty(filedb);
}
-/** enter atomic mode */
+/* see db.h */
int
db_transaction_begin(
) {
- int rc1, rc2;
+ int rc1, rc2, rc;
+
+ if (modifiable)
+ return -EALREADY;
rc1 = anydb_transaction(filedb, Anydb_Transaction_Start);
rc2 = anydb_transaction(memdb, Anydb_Transaction_Start);
- return rc1 ?: rc2;
+ rc = rc1 ?: rc2;
+ modifiable = !rc;
+
+ return rc;
}
-/** leave atomic mode */
+/* see db.h */
int
db_transaction_end(
bool commit
) {
int rc1, rc2, rc3, rc4;
+ if (!modifiable)
+ return -EALREADY;
+
if (commit) {
rc1 = anydb_transaction(filedb, Anydb_Transaction_Commit);
rc2 = anydb_transaction(memdb, Anydb_Transaction_Commit);
@@ -106,54 +125,61 @@ db_transaction_end(
rc3 = 0;
}
rc4 = db_sync();
+ modifiable = false;
return rc1 ?: rc2 ?: rc3 ?: rc4;
}
-/** enumerate */
+/* see db.h */
void
db_for_all(
- void *closure,
void (*callback)(
void *closure,
const data_key_t *key,
const data_value_t *value),
+ void *closure,
const data_key_t *key
) {
- anydb_for_all(filedb, closure, callback, key);
- anydb_for_all(memdb, closure, callback, key);
+ anydb_for_all(filedb, callback, closure, key);
+ anydb_for_all(memdb, callback, closure, key);
}
-/** drop rules */
+/* see db.h */
int
db_drop(
const data_key_t *key
) {
+ if (!modifiable)
+ return -EACCES;
+
anydb_drop(filedb, key);
anydb_drop(memdb, key);
return 0;
}
-/** set rules */
+/* see db.h */
int
db_set(
const data_key_t *key,
const data_value_t *value
) {
- if (is_any_or_wide(key->session))
- return anydb_set(filedb, key, value);
- else
- return anydb_set(memdb, key, value);
+ anydb_t *db;
+
+ if (!modifiable)
+ return -EACCES;
+
+ db = is_any_or_wide(key->session) ? filedb : memdb;
+ return anydb_set(db, key, value);
}
-/** check rules */
-int
+/* see db.h */
+unsigned
db_test(
const data_key_t *key,
data_value_t *value
) {
- int s1, s2;
+ unsigned s1, s2;
data_value_t v1, v2;
s1 = anydb_test(memdb, key, &v1);
@@ -161,12 +187,13 @@ db_test(
if (s2 > s1) {
*value = v2;
return s2;
- } else {
- *value = v1;
- return s1;
}
+ if (s1)
+ *value = v1;
+ return s1;
}
+/* see db.h */
int
db_cleanup(
) {
@@ -175,6 +202,7 @@ db_cleanup(
return 0;
}
+/* see db.h */
int
db_sync(
) {
diff --git a/src/db.h b/src/db.h
index edb4f29..0171c02 100644
--- a/src/db.h
+++ b/src/db.h
@@ -14,63 +14,94 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* INTERNAL DATABASE IMPLEMENTATION */
+/******************************************************************************/
+/******************************************************************************/
-#define MAX_NAME_LENGTH 32767
-
-/** open the database for files 'names' and 'rules' (can be NULL) */
+/**
+ * Open the database in the directory
+ *
+ * @param directory the directory containing the database
+ * @return 0 in case of success or a negative error code
+ *
+ * @see db_close
+ */
extern
int
db_open(
const char *directory
);
-/** close the database */
+/**
+ * close the database
+ */
extern
void
db_close(
);
-/** is the database empty */
+/**
+ * Is the database empty?
+ *
+ * @return true if empty or else false
+ */
extern
bool
db_is_empty(
);
-/** enter atomic mode */
+/**
+ * Enter atomic mode or cancelable mode
+ *
+ * @return 0 in case of success or a negative -errno like value
+ *
+ * @see db_transaction_end, db_drop, db_set
+ */
extern
int
db_transaction_begin(
);
-/** leave atomic mode */
+/**
+ * Leave atomic mode commiting or not the changes
+ *
+ * @param commit if true changes are commited otherwise, if false cancel them
+ * @return 0 in case of success or a negative -errno like value
+ *
+ * @see db_transaction_begin, db_drop, db_set
+ */
extern
int
db_transaction_end(
bool commit
);
-/** enumerate */
-extern
-void
-db_for_all(
- void *closure,
- void (*callback)(
- void *closure,
- const data_key_t *key,
- const data_value_t *value),
- const data_key_t *key
-);
-
-/** erase rules */
+/**
+ * Erase rules matching the key
+ *
+ * @param key the search key for the rules to remove
+ * @return 0 in case of success or a negative -errno like value
+ *
+ * @see db_transaction_begin, db_transaction_end, db_set
+ */
extern
int
db_drop(
const data_key_t *key
);
-/** set rules */
+/**
+ * Add the rule of key and value
+ *
+ * @param key the key of the rule to add
+ * @param value the value of the rule
+ * @return 0 in case of success or a negative -errno like value
+ *
+ * @see db_transaction_begin, db_transaction_end, db_drop
+ */
extern
int
db_set(
@@ -78,21 +109,54 @@ db_set(
const data_value_t *value
);
-/** check rules */
+/**
+ * Iterate over rules matching the key: call the callback for each found item
+ *
+ * @param callback the callback function to be call for each rule matching key
+ * @param closure the closure of the callback
+ * @param key the searching key
+ */
extern
-int
+void
+db_for_all(
+ void (*callback)(
+ void *closure,
+ const data_key_t *key,
+ const data_value_t *value),
+ void *closure,
+ const data_key_t *key
+);
+
+/**
+ * Get the rule value for the key
+ *
+ * @param key The key to query
+ * @param value Where to store the result if any
+ * @return 0 if no rule matched (value unchanged then) or a positive integer
+ * when a value was found for the key
+ */
+extern
+unsigned
db_test(
const data_key_t *key,
data_value_t *value
);
-/** cleanup the base */
+/**
+ * Cleanup the database by removing expired items
+ *
+ * @return 0 in case of success or a negative -errno like value
+ */
extern
int
db_cleanup(
);
-/** cleanup the base */
+/**
+ * Write the database to the file system (synchrnize it)
+ *
+ * @return 0 in case of success or a negative -errno like value
+ */
extern
int
db_sync(
diff --git a/src/dbinit.c b/src/dbinit.c
index b1b3c54..e2366ad 100644
--- a/src/dbinit.c
+++ b/src/dbinit.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* READING DATABASE RULE FILES FOR INITIALISATION */
+/******************************************************************************/
+/******************************************************************************/
#include <stdlib.h>
#include <time.h>
@@ -28,7 +33,7 @@
#include "expire.h"
#include "dbinit.h"
-/** initialize the database from file of 'path' */
+/* see dbinit.h */
int dbinit_add_file(const char *path)
{
int rc, lino;
@@ -115,8 +120,10 @@ error2:
fclose(f);
error:
if (rc)
+ /* cancel changes if error occured */
cyn_leave(dbinit_add_file, 0);
else {
+ /* commit the changes */
rc = cyn_leave(dbinit_add_file, 1);
if (rc < 0)
fprintf(stderr, "unable to commit content of file %s\n", path);
diff --git a/src/dbinit.h b/src/dbinit.h
index bca4afc..a546575 100644
--- a/src/dbinit.h
+++ b/src/dbinit.h
@@ -14,9 +14,53 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* READING DATABASE RULE FILES FOR INITIALISATION */
+/******************************************************************************/
+/******************************************************************************/
-extern int dbinit_add_file(const char *path);
+/**
+ * Add to the database the data from file of 'path'
+ *
+ * ---------------------------------------------------------------------------
+ * The file must be made of lines being either empty, comment or rule
+ *
+ * Empty lines or comment lines are ignored.
+ *
+ * An empty line only contains spaces and/or tabs
+ *
+ * A comment line start with the character #. It can be preceded by any count
+ * of spaces and/or tabs.
+ *
+ * Other lines are rules. They must be made of 6 fields separated by any count
+ * of space and/or tabs. Spaces and tabs at the begining of the line are
+ * ignored.
+ *
+ * The 6 fields of a rule are:
+ *
+ * CLIENT SESSION USER PERMISSION VALUE EXPIRATION
+ *
+ * CLIENT, SESSION, USER, PERMISSION are arbitrary strings. The single star
+ * mean 'any value'.
+ *
+ * Value must be a string of some meaning. Known values are:
+ *
+ * - yes: grant the permission
+ * - no: forbid the permission
+ * - @:...: agent at (@)
+ *
+ * Expiration can be expressed
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * @param path path of the initialization file
+ * @return 0 in case of success or a negative -errno like code
+ */
+extern
+int
+dbinit_add_file(
+ const char *path
+);
diff --git a/src/expire.c b/src/expire.c
index 68278ca..cfa5dff 100644
--- a/src/expire.c
+++ b/src/expire.c
@@ -14,18 +14,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* CONVERTION OF EXPIRATIONS TO AND FROM TEXT */
+/******************************************************************************/
+/******************************************************************************/
#include <time.h>
#include <string.h>
#include <stdio.h>
+#include "expire.h"
+
static const int SEC = 1;
static const int MIN = 60;
static const int HOUR = 60*60;
static const int DAY = 24*60*60;
static const int WEEK = 7*24*60*60;
-static const int YEAR = 365*24*60*60;
+static const int YEAR = 365*24*60*60 + 24*60*60/4;
+/* see expire.h */
time_t txt2exp(const char *txt)
{
time_t r, x;
@@ -39,7 +47,7 @@ time_t txt2exp(const char *txt)
while(*txt) {
x = 0;
while('0' <= *txt && *txt <= '9')
- x = 10 * x + (time_t)(*txt++ - '0');
+ x = (x << 3) + (x << 1) + (time_t)(*txt++ - '0');
switch(*txt) {
case 'y': r += x * YEAR; txt++; break;
case 'w': r += x * WEEK; txt++; break;
@@ -54,6 +62,7 @@ time_t txt2exp(const char *txt)
return r;
}
+/* see expire.h */
size_t exp2txt(time_t expire, char *buffer, size_t buflen)
{
char b[100];
diff --git a/src/expire.h b/src/expire.h
index c9e46bc..1de82c2 100644
--- a/src/expire.h
+++ b/src/expire.h
@@ -14,8 +14,47 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* CONVERTION OF EXPIRATIONS TO AND FROM TEXT */
+/******************************************************************************/
+/******************************************************************************/
+
+/**
+ * Converts the time of the string to an expiration
+ *
+ * The string code a time relative to now using the format
+ * XXXyXXXwXXXdXXXhXXXmXXXs where XXX are numbers.
+ *
+ * Examples:
+ * - 15 means 15 seconds
+ * - 4h15m30s means 4 hours 15 minutes 30 seconds
+ * - forever means forever
+ * - 2m2w means two months and 2 weeks
+ *
+ * @param txt the text to convert
+ * @return the value for the text
+ */
+extern
+time_t
+txt2exp(
+ const char *txt
+);
-extern time_t txt2exp(const char *txt);
-extern size_t exp2txt(time_t expire, char *buffer, size_t buflen);
+/**
+ * Converts the expiration in to its relative string representation
+ *
+ * @param expire the epiration to convert
+ * @param buffer the buffer where to store the converted string
+ * @param buflen length of the buffer
+ * @return the length of the resulting string, can be greater than buflen but
+ * in that case, no more than buflen characters are copied to buffer
+ */
+extern
+size_t
+exp2txt(
+ time_t expire,
+ char *buffer,
+ size_t buflen
+);
diff --git a/src/fbuf.c b/src/fbuf.c
index c4243e6..0c88fcb 100644
--- a/src/fbuf.c
+++ b/src/fbuf.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF BUFFERED FILES */
+/******************************************************************************/
+/******************************************************************************/
#include <assert.h>
#include <stdlib.h>
@@ -31,16 +36,28 @@
#include "fbuf.h"
-/** compute the size to allocate for ensuring 'sz' bytes */
+/**
+ * compute the size to allocate for ensuring 'sz' bytes
+ * @param sz the expected size
+ * @return a size greater than sz
+ */
static
uint32_t
get_asz(
uint32_t sz
) {
- return (sz & 0xfffffc00) + 0x000004cf;
+ uint32_t r = (sz & 0xfffffc00) + 0x000004cf;
+ return r > sz ? r : UINT32_MAX;
}
-/** open in 'fb' the file of 'name' */
+/**
+ * Open in 'fb' the file of 'name'
+ * @param fb the fbuf
+ * @param name the name of the file to read
+ * @return 0 on success
+ * -EFBIG if the file is too big
+ * -errno system error
+ */
static
int
read_file(
@@ -91,7 +108,7 @@ error:
return rc;
}
-/** open in 'fb' the file of 'name' */
+/* see fbuf.h */
int
fbuf_open(
fbuf_t *fb,
@@ -105,18 +122,19 @@ fbuf_open(
memset(fb, 0, sizeof *fb);
/* save name */
- fb->name = strdup(name);
+ sz = strlen(name);
+ fb->name = malloc(sz + 1);
if (fb->name == NULL)
goto error;
+ mempcpy(fb->name, name, sz + 1);
/* open the backup */
if (backup != NULL)
fb->backup = strdup(backup);
else {
- sz = strlen(name);
fb->backup = malloc(sz + 2);
if (fb->backup != NULL) {
- memcpy(fb->backup, name, sz);
+ mempcpy(fb->backup, name, sz);
fb->backup[sz] = '~';
fb->backup[sz + 1] = 0;
}
@@ -129,6 +147,7 @@ fbuf_open(
if (rc < 0)
goto error;
+ /* any read data is already saved */
fb->saved = fb->used;
return 0;
@@ -139,7 +158,7 @@ error:
return rc;
}
-/** close the file 'fb' */
+/* see fbuf.h */
void
fbuf_close(
fbuf_t *fb
@@ -150,7 +169,7 @@ fbuf_close(
memset(fb, 0, sizeof *fb);
}
-/** write to file 'fb' the unsaved bytes and flush the content to the file */
+/* see fbuf.h */
int
fbuf_sync(
fbuf_t *fb
@@ -173,6 +192,8 @@ fbuf_sync(
close(fd);
if (rcs < 0)
goto error;
+ if ((uint32_t)rcs != fb->used)
+ goto error; /* TODO: set some errno? */
fb->size = fb->saved = fb->used;
return 0;
@@ -183,29 +204,29 @@ error:
return rc;
}
-/** allocate enough memory in 'fb' to store 'count' bytes */
+/* see fbuf.h */
int
fbuf_ensure_capacity(
fbuf_t *fb,
- uint32_t count
+ uint32_t capacity
) {
- uint32_t capacity;
+ uint32_t asz;
void *buffer;
- if (count > fb->capacity) {
- capacity = get_asz(count);
- buffer = realloc(fb->buffer, capacity);
+ if (capacity > fb->capacity) {
+ asz = get_asz(capacity);
+ buffer = realloc(fb->buffer, asz);
if (buffer == NULL) {
- fprintf(stderr, "alloc %u for file %s failed: %m\n", capacity, fb->name);
+ fprintf(stderr, "alloc %u for file %s failed: %m\n", asz, fb->name);
return -ENOMEM;
}
fb->buffer = buffer;
- fb->capacity = capacity;
+ fb->capacity = asz;
}
return 0;
}
-/** put at 'offset' in the memory of 'fb' the 'count' bytes pointed by 'buffer' */
+/* see fbuf.h */
int
fbuf_put(
fbuf_t *fb,
@@ -214,12 +235,13 @@ fbuf_put(
uint32_t offset
) {
int rc;
- uint32_t end = offset + count;
+ uint32_t end;
/* don't call me for nothing */
assert(count);
/* grow as necessary */
+ end = offset + count;
if (end > fb->used) {
rc = fbuf_ensure_capacity(fb, end);
if (rc < 0)
@@ -236,7 +258,7 @@ fbuf_put(
return 0;
}
-/** append at end in the memory of 'fb' the 'count' bytes pointed by 'buffer' */
+/* see fbuf.h */
int
fbuf_append(
fbuf_t *fb,
@@ -249,7 +271,7 @@ fbuf_append(
return fbuf_put(fb, buffer, count, fb->used);
}
-/** check or make identification of file 'fb' by 'id' of 'len' */
+/* see fbuf.h */
int
fbuf_identify(
fbuf_t *fb,
@@ -265,12 +287,11 @@ fbuf_identify(
return 0;
/* bad identification */
- errno = ENOKEY;
fprintf(stderr, "identification of file %s failed: %m\n", fb->name);
return -ENOKEY;
}
-/** check or make identification by 'uuid' of file 'fb' */
+/* see fbuf.h */
int
fbuf_open_identify(
fbuf_t *fb,
@@ -281,16 +302,18 @@ fbuf_open_identify(
) {
int rc;
+ /* open the files */
rc = fbuf_open(fb, name, backup);
if (rc == 0) {
+ /* check identifier */
rc = fbuf_identify(fb, id, idlen);
if (rc < 0)
- fbuf_close(fb);
+ fbuf_close(fb); /* close if error */
}
return rc;
}
-/** make a backup */
+/* see fbuf.h */
int
fbuf_backup(
fbuf_t *fb
@@ -299,7 +322,7 @@ fbuf_backup(
return link(fb->name, fb->backup);
}
-/** recover from latest backup */
+/* see fbuf.h */
int
fbuf_recover(
fbuf_t *fb
diff --git a/src/fbuf.h b/src/fbuf.h
index 43909fa..ee9ac25 100644
--- a/src/fbuf.h
+++ b/src/fbuf.h
@@ -14,8 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF BUFFERED FILES */
+/******************************************************************************/
+/******************************************************************************/
/**
* A fbuf records file data and access
@@ -48,7 +52,14 @@ struct fbuf
typedef struct fbuf fbuf_t;
-/** open in 'fb' the file of 'name' and optionnal 'backup' name */
+/**
+ * open in 'fb' the file of 'name'
+ * @param fb the fbuf
+ * @param name name of the filename to read
+ * @param backup name of the backup to use (can be NULL)
+ * @return 0 on success
+ * a negative -errno code
+ */
extern
int
fbuf_open(
@@ -57,21 +68,35 @@ fbuf_open(
const char *backup
);
-/** close the file 'fb' */
+/**
+ * close the fbuf 'fb'
+ * @param fb the fbuf to close
+ */
extern
void
fbuf_close(
fbuf_t *fb
);
-/** write to file 'fb' the unsaved bytes and flush the content to the file */
+/**
+ * write to fbuf 'fb' the unsaved bytes and flush the content to the file
+ * @param fb the fbuf
+ * @return 0 on success
+ * a negative -errno code
+ */
extern
int
fbuf_sync(
fbuf_t *fb
);
-/** allocate enough memory in 'fb' to store 'count' bytes */
+/**
+ * allocate enough memory in 'fb' to store 'count' bytes
+ * @param fb the fbuf
+ * @param capacity expected capacity
+ * @return 0 on success
+ * -ENOMEM if out of memory
+ */
extern
int
fbuf_ensure_capacity(
@@ -79,7 +104,15 @@ fbuf_ensure_capacity(
uint32_t count
);
-/** put at 'offset' in the memory of 'fb' the 'count' bytes pointed by 'buffer' */
+/**
+ * put at 'offset' in the memory of 'fb' the 'count' bytes pointed by 'buffer'
+ * @param fb the fbuf
+ * @param buffer pointer to the data
+ * @param count size of data MUST BE GREATER THAN ZERO
+ * @param offset where to put the data
+ * @return 0 on success
+ * -ENOMEM if out of memory
+ */
extern
int
fbuf_put(
@@ -89,7 +122,14 @@ fbuf_put(
uint32_t offset
);
-/** append at end in the memory of 'fb' the 'count' bytes pointed by 'buffer' */
+/**
+ * append at end in the memory of 'fb' the 'count' bytes pointed by 'buffer'
+ * @param fb the fbuf
+ * @param buffer pointer to the data
+ * @param count size of data MUST BE GREATER THAN ZERO
+ * @return 0 on success
+ * -ENOMEM if out of memory
+ */
extern
int
fbuf_append(
@@ -98,7 +138,16 @@ fbuf_append(
uint32_t count
);
-/** check or make identification of file 'fb' by 'id' of 'len' */
+/**
+ * Check or make identification of file 'fb' by 'id' of 'idlen'
+ * If the content is empty, it initialize the identification prefix.
+ * Otherwise, not empty, the check is performed.
+ * @param fb the fbuf to check
+ * @param id the prefix identifier to check
+ * @param idlen the length of the identifier
+ * @return 0 on success
+ * -ENOKEY if identification failed
+ */
extern
int
fbuf_identify(
@@ -107,7 +156,19 @@ fbuf_identify(
uint32_t idlen
);
-/** check or make identification by 'uuid' of file 'fb' */
+/**
+ * Open the fbuf 'fb' of 'name', 'backup' and check that it has the
+ * prefix identifier 'id' of length 'idlen'.
+ * @param fb the fbuf to open
+ * @param name file name to open
+ * @param backup name of the backup file
+ * @param id identifier prefix value
+ * @param idlen length of the identifier prefix
+ * @return 0 in case of success
+ * -ENOMEM if out of memory
+ * -ENOKEY if identification failed
+ * a negative -errno code
+ */
extern
int
fbuf_open_identify(
@@ -118,12 +179,26 @@ fbuf_open_identify(
uint32_t idlen
);
+/**
+ * Create the back-up file
+ * Backup is managed using hard links. It implies that the operating system
+ * handles hard links.
+ * @param fb the fbuf
+ * @return 0 in case of success
+ * a negative -errno code
+ */
extern
int
fbuf_backup(
fbuf_t *fb
);
+/**
+ * recover data from latest backup
+ * @param fb the fbuf
+ * @return 0 on success
+ * a negative -errno code
+ */
extern
int
fbuf_recover(
diff --git a/src/filedb.c b/src/filedb.c
index ce37ad1..9a57a68 100644
--- a/src/filedb.c
+++ b/src/filedb.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF DATABASE WITH FILE BACKEND */
+/******************************************************************************/
+/******************************************************************************/
#include <assert.h>
#include <stdlib.h>
@@ -31,8 +36,6 @@
#include "fbuf.h"
#include "filedb.h"
-#define MAX_NAME_LENGTH 32768
-
/*
* for the first version, save enougth time up to 4149
* 4149 = 1970 + (4294967296 * 16) / (365 * 24 * 60 * 60)
@@ -125,11 +128,16 @@ struct filedb
bool has_backup;
/** the anydb interface */
- anydb_t db;
+ anydb_t anydb;
};
typedef struct filedb filedb_t;
-/** return the name of 'index' */
+/**
+ * Return the name of the given index
+ * @param filedb the database handler
+ * @param index index of the string MUST be valid
+ * @return the name for the index
+ */
static
const char*
name_at(
@@ -153,57 +161,62 @@ cmpnames(
return strcmp(name_at(filedb, a), name_at(filedb, b));
}
-/** initialize names */
+/**
+ * Initialize the fields 'names_sorted' and 'names_count' for the
+ * current database.
+ * @param filedb the database handler
+ * @return 0 in case of success or -ENOMEM or -ENOEXEC
+ */
static
int
init_names(
filedb_t *filedb
) {
- uint32_t pos, len, *ns, *p, all, nc;
+ uint32_t pos, length, *sorted, *p, allocated, name_count;
- all = 0;
- nc = 0;
- ns = NULL;
+ allocated = 0;
+ name_count = 0;
+ sorted = NULL;
/* iterate over names */
pos = uuidlen;
while (pos < filedb->fnames.used) {
/* get name length */
- len = (uint32_t)strlen(name_at(filedb, pos));
- if (pos + len <= pos || pos + len > filedb->fnames.used) {
- free(ns);
- goto bad_file;
+ length = (uint32_t)strlen(name_at(filedb, pos));
+ if (pos + length <= pos || pos + length > filedb->fnames.used) {
+ /* overflow */
+ free(sorted);
+ fprintf(stderr, "bad file %s\n", filedb->fnames.name);
+ return -ENOEXEC;
}
/* store the position */
- if (all <= nc) {
- all += 1024;
- p = realloc(ns, all * sizeof *ns);
+ if (allocated <= name_count) {
+ allocated += 1024;
+ p = realloc(sorted, allocated * sizeof *sorted);
if (p == NULL) {
- free(ns);
+ free(sorted);
fprintf(stderr, "out of memory\n");
- goto error;
+ return -ENOMEM;
}
- ns = p;
+ sorted = p;
}
- ns[nc++] = pos;
+ sorted[name_count++] = pos;
/* next */
- pos += len + 1;
+ pos += length + 1;
}
/* sort and record */
- qsort_r(ns, nc, sizeof *ns, cmpnames, filedb);
- filedb->names_sorted = ns;
- filedb->names_count = nc;
+ qsort_r(sorted, name_count, sizeof *sorted, cmpnames, filedb);
+ filedb->names_sorted = sorted;
+ filedb->names_count = name_count;
return 0;
-
-bad_file:
- fprintf(stderr, "bad file %s\n", filedb->fnames.name);
- errno = ENOEXEC;
-error:
- return -1;
}
-/** init the rules from the file */
+/**
+ * Initialize the fields 'rules' and 'rules_count' for the
+ * current database.
+ * @param filedb the database handler
+ */
static
void
init_rules(
@@ -213,7 +226,21 @@ init_rules(
filedb->rules_count = (filedb->frules.used - uuidlen) / sizeof *filedb->rules;
}
-/** open a fbuf */
+/**
+ * Open the fbuf 'fb' in the directory, the name and the extension.
+ * Check that the identifier prefix matches or if the file doesn't exist
+ * create the prefix.
+ * @param fb the buffer to open
+ * @param directory the directory containing the file
+ * @param name the basename for the file
+ * @param extension the extension of the file
+ * @param id the identifier prefix
+ * @param idlen the length of the identifier prefix
+ * @return 0 in case of success
+ * -ENOMEM if out of memory
+ * -ENOKEY if identification failed
+ * a negative -errno code
+ */
static
int
open_identify(
@@ -224,25 +251,38 @@ open_identify(
const char *id,
uint32_t idlen
) {
- char *file, *backup, *p;
+ char *file, *p;
size_t ldir, lext, lname;
+ /* compute sizes */
ldir = strlen(directory);
lname = strlen(name);
lext = strlen(extension);
- file = alloca(((ldir + lname + lext) << 1) + 7);
+
+ /* allocate memory for file */
+ file = alloca((ldir + lname + lext) + 3);
+
+ /* make the file's name: directory/name.extension */
p = mempcpy(file, directory, ldir);
*p++ = '/';
p = mempcpy(p, name, lname);
*p++ = '.';
- backup = mempcpy(p, extension, lext + 1);
- p = mempcpy(backup, file, ldir + lname + lext + 2);
- *p++ = '~';
- *p = 0;
- return fbuf_open_identify(fb, file, backup, id, idlen);
+ mempcpy(p, extension, lext + 1);
+
+ /* open the fbuf now */
+ return fbuf_open_identify(fb, file, NULL, id, idlen);
}
-/** open the database for files 'names' and 'rules' (can be NULL) */
+/**
+ * Open the database of 'name' in 'directory'
+ * @param filedb the database handler to open
+ * @param directory the directory containing the database (or null for default)
+ * @param name the basename for the file
+ * @return 0 in case of success
+ * -ENOMEM if out of memory
+ * -ENOKEY if identification failed
+ * a negative -errno code
+ */
static
int
opendb(
@@ -262,26 +302,27 @@ opendb(
/* open the names */
rc = open_identify(&filedb->fnames, directory, name, "names", uuid_names_v2, uuidlen);
- if (rc < 0)
- goto error;
-
- /* open the rules */
- rc = open_identify(&filedb->frules, directory, name, "rules", uuid_rules_v2, uuidlen);
- if (rc < 0)
- goto error;
-
- /* connect internals */
- rc = init_names(filedb);
- if (rc < 0)
- goto error;
-
- init_rules(filedb);
- return 0;
-error:
- return -1;
+ if (rc == 0) {
+ /* open the rules */
+ rc = open_identify(&filedb->frules, directory, name, "rules", uuid_rules_v2, uuidlen);
+ if (rc == 0) {
+ /* connect internals */
+ rc = init_names(filedb);
+ if (rc == 0) {
+ init_rules(filedb);
+ return 0;
+ }
+ fbuf_close(&filedb->frules);
+ }
+ fbuf_close(&filedb->fnames);
+ }
+ return rc;
}
-/** close the database */
+/**
+ * Close the database
+ * @param filedb database to close
+ */
static
void
closedb(
@@ -292,7 +333,12 @@ closedb(
fbuf_close(&filedb->frules);
}
-/** synchronize db on files */
+/**
+ * Synchronize database and its files (write it to the filesystem)
+ * @param filedb database to synchronize
+ * @return 0 in case of success
+ * a negative -errno code
+ */
static
int
syncdb(
@@ -302,10 +348,12 @@ syncdb(
assert(filedb->fnames.name && filedb->frules.name);
if (!filedb->is_changed)
- rc = 0;
+ rc = 0; /* unchanged */
else {
+ /* sync the names */
rc = fbuf_sync(&filedb->fnames);
if (rc == 0) {
+ /* sync the rules */
rc = fbuf_sync(&filedb->frules);
if (rc == 0) {
filedb->is_changed = false;
@@ -316,7 +364,12 @@ syncdb(
return rc;
}
-/** make a backup of the database */
+/**
+ * Creates backups of the database
+ * @param filedb the database to backup
+ * @return 0 in case of success
+ * a negative -errno code
+ */
static
int
backupdb(
@@ -326,21 +379,26 @@ backupdb(
assert(filedb->fnames.name && filedb->frules.name);
if (filedb->has_backup)
- rc = 0;
+ rc = 0; /* already backuped */
else {
+ /* backup names */
rc = fbuf_backup(&filedb->fnames);
if (rc == 0) {
+ /* backup rules */
rc = fbuf_backup(&filedb->frules);
- if (rc == 0) {
+ if (rc == 0)
filedb->has_backup = true;
- filedb->is_changed = false;
- }
}
}
return rc;
}
-/** recover the database from latest backup */
+/**
+ * recover the database from latest backup
+ * @param filedb database to recover
+ * @return 0 in case of success
+ * a negative -errno code
+ */
static
int
recoverdb(
@@ -352,14 +410,17 @@ recoverdb(
if (!filedb->is_changed || !filedb->has_backup)
rc = 0;
else {
+ /* recover names */
rc = fbuf_recover(&filedb->fnames);
if (rc < 0)
goto error;
+ /* recover rules */
rc = fbuf_recover(&filedb->frules);
if (rc < 0)
goto error;
+ /* init names */
rc = init_names(filedb);
if (rc < 0)
goto error;
@@ -375,6 +436,7 @@ error:
return rc;
}
+/** implementation of anydb_itf.index */
static
int
index_itf(
@@ -446,6 +508,7 @@ index_itf(
return 0;
}
+/** implementation of anydb_itf.string */
static
const char *
string_itf(
@@ -454,14 +517,16 @@ string_itf(
) {
filedb_t *filedb = clodb;
+ assert(idx < filedb->fnames.used);
return name_at(filedb, idx);
}
+/** implementation of anydb_itf.apply */
static
void
apply_itf(
void *clodb,
- anydb_action_t (*oper)(void *closure, const anydb_key_t *key, anydb_value_t *value),
+ anydb_applycb_t *oper,
void *closure
) {
filedb_t *filedb = clodb;
@@ -469,7 +534,7 @@ apply_itf(
rule_t *rule;
anydb_key_t key;
anydb_value_t value;
- uint32_t i;
+ uint32_t i, saved;
key.session = AnyIdx_Wide;
i = 0;
@@ -481,29 +546,30 @@ apply_itf(
value.value = rule->value;
value.expire = exp2time(rule->expire);
a = oper(closure, &key, &value);
- switch (a) {
- case Anydb_Action_Stop:
- return;
- case Anydb_Action_Continue:
- i++;
- break;
- case Anydb_Action_Update_And_Stop:
- rule->value = value.value;
- rule->expire = time2exp(value.expire);
- filedb->need_cleanup = true;
- filedb->is_changed = true;
- filedb->frules.saved = (uint32_t)((void*)rule - filedb->frules.buffer);
- return;
- case Anydb_Action_Remove_And_Continue:
+ if (a & Anydb_Action_Remove) {
*rule = filedb->rules[--filedb->rules_count];
filedb->is_changed = true;
filedb->need_cleanup = true;
+ saved = (uint32_t)((void*)rule - filedb->frules.buffer);
+ if (saved < filedb->frules.saved)
+ filedb->frules.saved = saved;
filedb->frules.used -= (uint32_t)sizeof *rule;
- break;
+ } else if (a & Anydb_Action_Update) {
+ rule->value = value.value;
+ rule->expire = time2exp(value.expire);
+ filedb->need_cleanup = true;
+ filedb->is_changed = true;
+ saved = (uint32_t)((void*)rule - filedb->frules.buffer);
+ if (saved < filedb->frules.saved)
+ filedb->frules.saved = saved;
}
+ if (a & Anydb_Action_Stop)
+ return;
+ i += !(a & Anydb_Action_Remove);
}
}
+/** implementation of anydb_itf.transaction */
static
int
transaction_itf(
@@ -531,6 +597,7 @@ transaction_itf(
return rc;
}
+/** implementation of anydb_itf.add */
static
int
add_itf(
@@ -562,6 +629,16 @@ add_itf(
return 0;
}
+/**
+ * Search (dig) dichotomically in 'array' of 'count' elements the index of
+ * 'item'. Store '*index' either the index of the found item or the index
+ * where inserting the item. Return true if found of false otherwise.
+ * @param array array to dig
+ * @param count count of elements in array
+ * @param item item to dig
+ * @param index where to store the found index
+ * @return true if found of false otherwise.
+ */
static
bool
gc_dig(
@@ -593,6 +670,13 @@ gc_dig(
return false;
}
+/**
+ * Add dichotomically the 'item' in the 'array' of 'count' elements
+ * @param array array to alter
+ * @param count count of element in the input array
+ * @param item the item to add
+ * @return the new count of elements
+ */
static
uint32_t
gc_add(
@@ -602,18 +686,29 @@ gc_add(
) {
uint32_t index, i;
+ /* search the item */
if (gc_dig(array, count, item, &index))
- return count;
+ return count; /* already in */
+ /* shift the elemetns above index */
i = count;
while (i > index) {
array[i] = array[i - 1];
i = i - 1;
}
+
+ /* add the item */
array[i] = item;
return count + 1;
}
+/**
+ * Mark in 'array' of 'count' elements the 'item'
+ * @param array the sorted array of marked items
+ * @param count the count of marked items
+ * @param item the item to mark
+ * @return the new count of marked items
+ */
static
uint32_t
gc_mark(
@@ -624,30 +719,60 @@ gc_mark(
return item > AnyIdx_Max ? count : gc_add(array, count, item);
}
+/**
+ * Test if 'item' is marked in 'array' of 'count' marked elements
+ * @param array the sorted array of marked items
+ * @param count the count of marked items
+ * @param item the item to search
+ * @param index where to store the index of the item if found
+ * @return true is found (marked) or false otherwise (not marked)
+ */
static
bool
-gc_new(
+gc_is_marked(
uint32_t *array,
uint32_t count,
uint32_t item,
uint32_t *index
) {
- return item > AnyIdx_Max ? false : gc_dig(array, count, item, index);
+ return item <= AnyIdx_Max && gc_dig(array, count, item, index);
+}
+
+/**
+ * Translate the item pointed by 'item' to its new value after renumeration
+ * @param marked the sorted array of marked items
+ * @param renum the renumerotation of the marked items
+ * @param count the count of marked items
+ * @param item the pointer to the item to modify
+ */
+static
+void
+gc_renum(
+ uint32_t *marked,
+ uint32_t *renum,
+ uint32_t count,
+ uint32_t *item
+) {
+ uint32_t index;
+
+ if (gc_is_marked(marked, count, *item, &index))
+ *item = renum[index];
}
+/** implementation of anydb_itf.gc */
static
void
gc_itf(
void *clodb
) {
filedb_t *filedb = clodb;
- uint32_t nr;
- uint32_t nn;
+ uint32_t rule_count;
+ uint32_t name_count;
struct rule *rules;
- uint32_t *used;
- uint32_t *sorted;
+ uint32_t *marked;
+ uint32_t *renum;
char *strings;
- uint32_t ir, nu, idx, is, ios, lenz;
+ uint32_t irule, new_count, imarked, istr_before, istr_after, lenz;
/* check cleanup required */
if (!filedb->need_cleanup)
@@ -655,60 +780,57 @@ gc_itf(
filedb->need_cleanup = false;
/* mark items */
- nr = filedb->rules_count;
- nn = filedb->names_count;
+ rule_count = filedb->rules_count;
+ name_count = filedb->names_count;
rules = filedb->rules;
- used = alloca(nn * sizeof *used);
- nu = 0;
- for (ir = 0 ; ir < nr ; ir++) {
- nu = gc_mark(used, nu, rules[ir].client);
- nu = gc_mark(used, nu, rules[ir].user);
- nu = gc_mark(used, nu, rules[ir].permission);
- nu = gc_mark(used, nu, rules[ir].value);
+ marked = alloca(name_count * sizeof *marked);
+ new_count = 0;
+ for (irule = 0 ; irule < rule_count ; irule++) {
+ new_count = gc_mark(marked, new_count, rules[irule].client);
+ new_count = gc_mark(marked, new_count, rules[irule].user);
+ new_count = gc_mark(marked, new_count, rules[irule].permission);
+ new_count = gc_mark(marked, new_count, rules[irule].value);
}
/* pack if too much unused */
- if (nu + (nu >> 2) <= nn)
+ if (new_count + (new_count >> 2) >= name_count)
return;
- /* pack the names */
+ /* pack the names by removing the unused strings */
strings = (char*)filedb->fnames.buffer;
- sorted = filedb->names_sorted;
- is = ios = uuidlen;
- while (is < filedb->fnames.used) {
+ renum = filedb->names_sorted;
+ istr_before = istr_after = uuidlen;
+ while (istr_before < filedb->fnames.used) {
/* get name length */
- lenz = 1 + (uint32_t)strlen(strings + is);
- if (gc_dig(used, nu, is, &idx)) {
- sorted[idx] = ios;
- if (is != ios)
- memcpy(strings + ios, strings + is, lenz);
- ios += lenz;
+ lenz = 1 + (uint32_t)strlen(strings + istr_before);
+ if (gc_is_marked(marked, new_count, istr_before, &imarked)) {
+ renum[imarked] = istr_after;
+ if (istr_before != istr_after)
+ memcpy(strings + istr_after, strings + istr_before, lenz);
+ istr_after += lenz;
}
/* next */
- is += lenz;
+ istr_before += lenz;
}
/* renum the rules */
- for (ir = 0 ; ir < nr ; ir++) {
- if (gc_new(used, nu, rules[ir].client, &idx))
- rules[ir].client = sorted[idx];
- if (gc_new(used, nu, rules[ir].user, &idx))
- rules[ir].user = sorted[idx];
- if (gc_new(used, nu, rules[ir].permission, &idx))
- rules[ir].permission = sorted[idx];
- if (gc_new(used, nu, rules[ir].value, &idx))
- rules[ir].value = sorted[idx];
+ for (irule = 0 ; irule < rule_count ; irule++) {
+ gc_renum(marked, renum, new_count, &rules[irule].client);
+ gc_renum(marked, renum, new_count, &rules[irule].user);
+ gc_renum(marked, renum, new_count, &rules[irule].permission);
+ gc_renum(marked, renum, new_count, &rules[irule].value);
}
/* record and sort */
- filedb->names_count = nu;
- filedb->fnames.used = ios;
- qsort_r(sorted, nu, sizeof *sorted, cmpnames, filedb);
+ filedb->names_count = new_count;
+ filedb->fnames.used = istr_after;
+ qsort_r(renum, new_count, sizeof *renum, cmpnames, filedb);
/* set as changed */
filedb->is_changed = true;
}
+/** implementation of anydb_itf.sync */
static
int
sync_itf(
@@ -718,6 +840,7 @@ sync_itf(
return syncdb(filedb);
}
+/** implementation of anydb_itf.destroy */
static
void
destroy_itf(
@@ -731,23 +854,28 @@ destroy_itf(
}
}
+/**
+ * Initialize the anydb interface of filedb
+ * @param filedb the structure to initialize
+ */
static
void
-init(
+init_anydb_itf(
filedb_t *filedb
) {
- filedb->db.clodb = filedb;
-
- filedb->db.itf.index = index_itf;
- filedb->db.itf.string = string_itf;
- filedb->db.itf.transaction = transaction_itf;
- filedb->db.itf.apply = apply_itf;
- filedb->db.itf.add = add_itf;
- filedb->db.itf.gc = gc_itf;
- filedb->db.itf.sync = sync_itf;
- filedb->db.itf.destroy = destroy_itf;
+ filedb->anydb.clodb = filedb;
+
+ filedb->anydb.itf.index = index_itf;
+ filedb->anydb.itf.string = string_itf;
+ filedb->anydb.itf.transaction = transaction_itf;
+ filedb->anydb.itf.apply = apply_itf;
+ filedb->anydb.itf.add = add_itf;
+ filedb->anydb.itf.gc = gc_itf;
+ filedb->anydb.itf.sync = sync_itf;
+ filedb->anydb.itf.destroy = destroy_itf;
}
+/* see filedb.h */
int
filedb_create(
anydb_t **adb,
@@ -757,25 +885,21 @@ filedb_create(
int rc;
filedb_t *filedb;
+ /* allocates */
*adb = NULL;
filedb = calloc(1, sizeof *filedb);
if (!filedb)
return -ENOMEM;
- init(filedb);
+ /* init anydb interface */
+ init_anydb_itf(filedb);
+ /* open the database file */
rc = opendb(filedb, directory, basename);
if (rc)
free(filedb);
else
- *adb = &filedb->db;
+ *adb = &filedb->anydb;
return rc;
}
-/** synchronize database */
-int
-anydb_sync(
- anydb_t *db
-) {
- return db->itf.sync ? db->itf.sync(db->clodb) : 0;
-}
diff --git a/src/filedb.h b/src/filedb.h
index d575e50..85d6c26 100644
--- a/src/filedb.h
+++ b/src/filedb.h
@@ -14,11 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF DATABASE WITH FILE BACKEND */
+/******************************************************************************/
+/******************************************************************************/
-
-/** is the database empty */
+/**
+ * Create the object handling the file database
+ * @param filedb pointer to the handling object to return
+ * @param directory the directory of the database
+ * @param basename the basename of the database
+ * @return 0 in case of success with *filedb fulfilled or negative -errno error
+ */
int
filedb_create(
anydb_t **filedb,
diff --git a/src/lib-compat.c b/src/lib-compat.c
index eb98895..63696fe 100644
--- a/src/lib-compat.c
+++ b/src/lib-compat.c
@@ -14,7 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+/******************************************************************************/
+/******************************************************************************/
+/* COMPATIBILITY LAYER TO PREVIOUS CYNARA */
+/******************************************************************************/
+/******************************************************************************/
/*
cynara_admin_initialize(&m_CynaraAdmin),
cynara_admin_finish(m_CynaraAdmin);
diff --git a/src/main-cynadm.c b/src/main-cynadm.c
index e099d64..9f3a179 100644
--- a/src/main-cynadm.c
+++ b/src/main-cynadm.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF CYNARA ADMINISTRATION TOOL */
+/******************************************************************************/
+/******************************************************************************/
#include <stdint.h>
#include <stdbool.h>
diff --git a/src/main-cynarad.c b/src/main-cynarad.c
index 2b8b0d3..6ed1878 100644
--- a/src/main-cynarad.c
+++ b/src/main-cynarad.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF CYNARA SERVER */
+/******************************************************************************/
+/******************************************************************************/
#include <stdlib.h>
#include <stdint.h>
diff --git a/src/memdb.c b/src/memdb.c
index 285d7a4..a67d1ef 100644
--- a/src/memdb.c
+++ b/src/memdb.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF IN MEMORY DATABASE WITHOUT FILE BACKEND */
+/******************************************************************************/
+/******************************************************************************/
#include <stdlib.h>
#include <stdint.h>
@@ -21,51 +26,76 @@
#include <time.h>
#include <string.h>
#include <errno.h>
+#include <assert.h>
#include "data.h"
#include "anydb.h"
+#include "memdb.h"
-#define RBS 20 /**< rule block size */
-#define SBS 30 /**< string bloc size */
+#define RULE_BLOC_SIZE 20 /**< rule block size */
+#define STRING_BLOC_SIZE 30 /**< string bloc size */
-#define TCLE 0 /**< tag for clean */
-#define TDEL 1 /**< tag for deleted */
-#define TMOD 2 /**< tag for modified */
+#define TAG_CLEAN 0 /**< tag for clean */
+#define TAG_DELETED 1 /**< tag for deleted */
+#define TAG_CHANGED 2 /**< tag for modified */
+/**
+ * structure for rules of memory database
+ */
struct rule
{
+ /** the key */
anydb_key_t key;
+
+ /** the current value */
anydb_value_t value;
+
+ /** the next value (depends on tag) */
anydb_value_t saved;
+
+ /** tag for the value saved */
uint8_t tag;
};
+/**
+ * Structure for the memory database
+ */
struct memdb
{
- /* first for the fun */
+ /** first for the fun */
anydb_t db;
- /* strings */
+ /** strings */
struct {
+ /** allocated count for strings */
uint32_t alloc;
+ /** used count for strings */
uint32_t count;
+ /** array of strings */
char **values;
} strings;
- /* rules */
+ /** rules */
struct {
+ /** allocated count for rules */
uint32_t alloc;
+ /** used count for rules */
uint32_t count;
+ /** array of rules */
struct rule *values;
} rules;
+ /** transaction */
struct {
+ /** rule count at the beginning of the transaction */
uint32_t count;
+ /** indicator for an active transaction */
bool active;
} transaction;
};
typedef struct memdb memdb_t;
+/** implementation of anydb_itf.index */
static
int
index_itf(
@@ -99,13 +129,14 @@ index_itf(
if (s == NULL)
return -ENOMEM;
if (memdb->strings.count == memdb->strings.alloc) {
- strings = realloc(strings, (memdb->strings.alloc + SBS) * sizeof *strings);
+ strings = realloc(strings, (memdb->strings.alloc
+ + STRING_BLOC_SIZE) * sizeof *strings);
if (!strings) {
free(s);
return -ENOMEM;
}
memdb->strings.values = strings;
- memdb->strings.alloc += SBS;
+ memdb->strings.alloc += STRING_BLOC_SIZE;
}
i = memdb->strings.count;
*idx = i;
@@ -114,6 +145,7 @@ index_itf(
return 0;
}
+/** implementation of anydb_itf.string */
static
const char *
string_itf(
@@ -122,14 +154,16 @@ string_itf(
) {
memdb_t *memdb = clodb;
+ assert(idx < memdb->strings.count);
return memdb->strings.values[idx];
}
+/** implementation of anydb_itf.apply */
static
void
apply_itf(
void *clodb,
- anydb_action_t (*oper)(void *closure, const anydb_key_t *key, anydb_value_t *value),
+ anydb_applycb_t *oper,
void *closure
) {
memdb_t *memdb = clodb;
@@ -139,32 +173,29 @@ apply_itf(
ir = 0;
while (ir < memdb->rules.count) {
- if (memdb->transaction.active && rules[ir].tag == TDEL)
- a = Anydb_Action_Continue;
- else
- a = oper(closure, &rules[ir].key, &rules[ir].value);
- switch (a) {
- case Anydb_Action_Stop:
- return;
- case Anydb_Action_Continue:
+ if (memdb->transaction.active && rules[ir].tag == TAG_DELETED)
ir++;
- break;
- case Anydb_Action_Update_And_Stop:
- if (memdb->transaction.active)
- rules[ir].tag = TMOD;
- else
- rules[ir].saved = rules[ir].value;
- return;
- case Anydb_Action_Remove_And_Continue:
- if (memdb->transaction.active)
- rules[ir++].tag = TDEL;
- else
- rules[ir] = rules[--memdb->rules.count];
- break;
+ else {
+ a = oper(closure, &rules[ir].key, &rules[ir].value);
+ if (a & Anydb_Action_Remove) {
+ if (memdb->transaction.active)
+ rules[ir++].tag = TAG_DELETED;
+ else
+ rules[ir] = rules[--memdb->rules.count];
+ } else if (a & Anydb_Action_Update) {
+ if (memdb->transaction.active)
+ rules[ir].tag = TAG_CHANGED;
+ else
+ rules[ir].saved = rules[ir].value;
+ }
+ if (a & Anydb_Action_Stop)
+ return;
+ ir += !(a & Anydb_Action_Remove);
}
}
}
+/** implementation of anydb_itf.transaction */
static
int
transaction_itf(
@@ -191,14 +222,14 @@ transaction_itf(
ir = 0;
while(ir < count) {
switch (rules[ir].tag) {
- case TCLE:
+ case TAG_CLEAN:
ir++;
break;
- case TDEL:
+ case TAG_DELETED:
rules[ir] = rules[--count];
break;
- case TMOD:
- rules[ir++].tag = TCLE;
+ case TAG_CHANGED:
+ rules[ir++].tag = TAG_CLEAN;
break;
}
}
@@ -211,9 +242,9 @@ transaction_itf(
rules = memdb->rules.values;
count = memdb->rules.count = memdb->transaction.count;
for (ir = 0 ; ir < count ; ir++) {
- if (rules[ir].tag != TCLE) {
+ if (rules[ir].tag != TAG_CLEAN) {
rules[ir].value = rules[ir].saved;
- rules[ir].tag = TCLE;
+ rules[ir].tag = TAG_CLEAN;
}
}
memdb->transaction.active = false;
@@ -222,6 +253,7 @@ transaction_itf(
return 0;
}
+/** implementation of anydb_itf.add */
static
int
add_itf(
@@ -238,7 +270,7 @@ add_itf(
count = memdb->rules.count;
alloc = memdb->rules.alloc;
if (count == alloc) {
- alloc += RBS;
+ alloc += RULE_BLOC_SIZE;
rules = realloc(rules, alloc * sizeof *rules);
if (!rules)
return -ENOMEM;
@@ -248,11 +280,16 @@ add_itf(
rules = &rules[count];
rules->key = *key;
rules->saved = rules->value = *value;
- rules->tag = TCLE;
+ rules->tag = TAG_CLEAN;
memdb->rules.count = count + 1;
return 0;
}
+/**
+ * Mark the 'item' as being used
+ * @param renum array handling marked items
+ * @param item the item to check
+ */
static
void
gc_mark(
@@ -263,32 +300,38 @@ gc_mark(
renum[item] = 1;
}
+/**
+ * return the renumring of 'item' within 'renum'
+ * @param renum the renumbering array
+ * @param item the item to renumber
+ * @return the renumbered item
+ */
static
anydb_idx_t
-gc_new(
+gc_renum(
anydb_idx_t *renum,
anydb_idx_t item
) {
return item > AnyIdx_Max ? item : renum[item];
}
-#include <stdio.h>
+
+/** implementation of anydb_itf.gc */
static
void
gc_itf(
void *clodb
) {
memdb_t *memdb = clodb;
- uint32_t nr = memdb->rules.count;
- uint32_t ns = memdb->strings.count;
+ uint32_t i, j;
+ uint32_t rule_count = memdb->rules.count;
+ uint32_t name_count = memdb->strings.count;
char **strings = memdb->strings.values;
struct rule *rules = memdb->rules.values;
- anydb_idx_t *renum = alloca(ns * sizeof *renum);
- uint32_t i, j;
-
- for (i = 0 ; i < ns ; i++)
- renum[i] = 0;
+ anydb_idx_t *renum = alloca(name_count * sizeof *renum);
- for (i = 0 ; i < nr ; i++) {
+ /* mark used strings */
+ memset(renum, 0, name_count * sizeof *renum);
+ for (i = 0 ; i < rule_count ; i++) {
gc_mark(renum, rules[i].key.client);
gc_mark(renum, rules[i].key.session);
gc_mark(renum, rules[i].key.user);
@@ -296,7 +339,8 @@ gc_itf(
gc_mark(renum, rules[i].value.value);
}
- for (i = j = 0 ; i < ns ; i++) {
+ /* pack the used strings */
+ for (i = j = 0 ; i < name_count ; i++) {
if (renum[i]) {
strings[j] = strings[i];
renum[i] = j++;
@@ -305,34 +349,38 @@ gc_itf(
renum[i] = AnyIdx_Invalid;
}
}
- if (ns != j) {
- memdb->strings.count = ns = j;
- for (i = 0 ; i < nr ; i++) {
- rules[i].key.client = gc_new(renum, rules[i].key.client);
- rules[i].key.session = gc_new(renum, rules[i].key.session);
- rules[i].key.user = gc_new(renum, rules[i].key.user);
- rules[i].key.permission = gc_new(renum, rules[i].key.permission);
- rules[i].value.value = gc_new(renum, rules[i].value.value);
+ if (name_count != j) {
+ /* renumber the items of the database */
+ memdb->strings.count = name_count = j;
+ for (i = 0 ; i < rule_count ; i++) {
+ rules[i].key.client = gc_renum(renum, rules[i].key.client);
+ rules[i].key.session = gc_renum(renum, rules[i].key.session);
+ rules[i].key.user = gc_renum(renum, rules[i].key.user);
+ rules[i].key.permission = gc_renum(renum, rules[i].key.permission);
+ rules[i].value.value = gc_renum(renum, rules[i].value.value);
}
}
+ /* decrease size of array for strings */
i = memdb->strings.alloc;
- while (ns + SBS < i)
- i -= SBS;
+ while (name_count + STRING_BLOC_SIZE < i)
+ i -= STRING_BLOC_SIZE;
if (i != memdb->strings.alloc) {
memdb->strings.alloc = i;
memdb->strings.values = realloc(strings, i * sizeof *strings);
}
+ /* decrease size of array for rules */
i = memdb->rules.alloc;
- while (nr + RBS < i)
- i -= RBS;
+ while (rule_count + RULE_BLOC_SIZE < i)
+ i -= RULE_BLOC_SIZE;
if (i != memdb->rules.alloc) {
memdb->rules.alloc = i;
- memdb->rules.values = realloc(rules, i * sizeof *strings);
+ memdb->rules.values = realloc(rules, i * sizeof *rules);
}
}
+/** implementation of anydb_itf.destroy */
static
void
destroy_itf(
@@ -346,9 +394,13 @@ destroy_itf(
}
}
+/**
+ * Initialize the structure of the memory database
+ * @param memdb the structure to initialize
+ */
static
void
-init(
+init_memdb(
memdb_t *memdb
) {
memdb->db.clodb = memdb;
@@ -374,18 +426,22 @@ init(
memdb->transaction.active = false;
}
+/* see memdb.h */
int
memdb_create(
anydb_t **memdb
) {
memdb_t *mdb;
+ /* allocate */
mdb = malloc(sizeof *mdb);
if (!mdb) {
*memdb = NULL;
return -ENOMEM;
}
- init(mdb);
+
+ /* init */
+ init_memdb(mdb);
*memdb = &mdb->db;
return 0;
}
diff --git a/src/memdb.h b/src/memdb.h
index 0f1c9e7..a947296 100644
--- a/src/memdb.h
+++ b/src/memdb.h
@@ -14,9 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF IN MEMORY DATABASE WITHOUT FILE BACKEND */
+/******************************************************************************/
+/******************************************************************************/
+/**
+ * Create the object handling the memory database
+ * @param memdb pointer to the handling object to return
+ */
extern
int
memdb_create(
diff --git a/src/pollitem.c b/src/pollitem.c
index d183594..22d2505 100644
--- a/src/pollitem.c
+++ b/src/pollitem.c
@@ -14,27 +14,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF EPOLL HELPER */
+/******************************************************************************/
+/******************************************************************************/
#include <stdint.h>
#include <sys/epoll.h>
-/*
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <poll.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-*/
-
#include "pollitem.h"
+/**
+ * Wraps the call to epoll_ctl for operation 'op'
+ *
+ * @param pollitem the pollitem to process
+ * @param events the expected events
+ * @param pollfd the file descriptor for epoll
+ * @param op the operation to perform
+ * @return 0 on success or -1 with errno set accordingly to epoll_ctl
+ */
static
int
pollitem_do(
@@ -47,6 +46,7 @@ pollitem_do(
return epoll_ctl(pollfd, op, pollitem->fd, &ev);
}
+/* see pollitem.h */
int
pollitem_add(
pollitem_t *pollitem,
@@ -56,6 +56,7 @@ pollitem_add(
return pollitem_do(pollitem, events, pollfd, EPOLL_CTL_ADD);
}
+/* see pollitem.h */
int
pollitem_mod(
pollitem_t *pollitem,
@@ -65,6 +66,7 @@ pollitem_mod(
return pollitem_do(pollitem, events, pollfd, EPOLL_CTL_MOD);
}
+/* see pollitem.h */
int
pollitem_del(
pollitem_t *pollitem,
@@ -73,6 +75,7 @@ pollitem_del(
return pollitem_do(pollitem, 0, pollfd, EPOLL_CTL_DEL);
}
+/* see pollitem.h */
int
pollitem_wait_dispatch(
int pollfd,
diff --git a/src/pollitem.h b/src/pollitem.h
index a60b7b8..375c674 100644
--- a/src/pollitem.h
+++ b/src/pollitem.h
@@ -14,22 +14,39 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF EPOLL HELPER */
+/******************************************************************************/
+/******************************************************************************/
/** structure for using epoll easily */
typedef struct pollitem pollitem_t;
+/**
+ * Structure for using epoll easily
+ */
struct pollitem
{
/** callback on event */
void (*handler)(pollitem_t *pollitem, uint32_t events, int pollfd);
- /** data */
+ /** data of any kind free to use */
void *closure;
- /** file */
+ /** file descriptor */
int fd;
};
+/**
+ * Add a pollitem to epoll
+ *
+ * @param pollitem the pollitem to add
+ * @param events expected events
+ * @param pollfd file descriptor of the epoll
+ * @return 0 on success or -1 with errno set accordingly to epoll_ctl
+ */
extern
int
pollitem_add(
@@ -38,6 +55,14 @@ pollitem_add(
int pollfd
);
+/**
+ * Modify a pollitem of epoll
+ *
+ * @param pollitem the pollitem to modify
+ * @param events expected events
+ * @param pollfd file descriptor of the epoll
+ * @return 0 on success or -1 with errno set accordingly to epoll_ctl
+ */
extern
int
pollitem_mod(
@@ -46,6 +71,13 @@ pollitem_mod(
int pollfd
);
+/**
+ * Delete a pollitem from epoll
+ *
+ * @param pollitem the pollitem to delete
+ * @param pollfd file descriptor of the epoll
+ * @return 0 on success or -1 with errno set accordingly to epoll_ctl
+ */
extern
int
pollitem_del(
@@ -53,6 +85,15 @@ pollitem_del(
int pollfd
);
+/**
+ * Wait one event on epoll and dispatch it to its pollitem callback
+ *
+ * @param pollfd file descriptor of the epoll
+ * @param timeout time to wait
+ * @return 0 on timeout
+ * 1 if a callback was called
+ * -1 with errno set accordingly to epoll_wait
+ */
extern
int
pollitem_wait_dispatch(
diff --git a/src/prot.c b/src/prot.c
index 06edb2f..7edcc50 100644
--- a/src/prot.c
+++ b/src/prot.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF THE PROTOCOL */
+/******************************************************************************/
+/******************************************************************************/
#include <stdlib.h>
#include <limits.h>
@@ -26,7 +31,15 @@
#include "prot.h"
-/** the structure buf is generic the meaning of pos/count is not fixed */
+#define MAX_FIELDS 20
+#define MAX_BUFFER_LENGTH 2000
+#define FIELD_SEPARATOR ' '
+#define RECORD_SEPARATOR '\n'
+#define ESCAPE '\\'
+
+/**
+ * the structure buf is generic the meaning of pos/count is not fixed
+ */
struct buf
{
/** a position */
@@ -38,7 +51,7 @@ struct buf
/* TODO: add a 3rd unsigned for improving management of read and write */
/** a fixed size content */
- char content[MAXBUFLEN];
+ char content[MAX_BUFFER_LENGTH];
};
typedef struct buf buf_t;
@@ -49,11 +62,13 @@ struct fields
int count;
/** the fields as strings */
- const char *fields[MAXARGS];
+ const char *fields[MAX_FIELDS];
};
typedef struct fields fields_t;
-/** structure for handling the protocol */
+/**
+ * structure for handling the protocol
+ */
struct prot
{
/** input buf, pos is the scanning position */
@@ -65,14 +80,13 @@ struct prot
/** count of pending output fields */
unsigned outfields;
- /** cancel index value value */
+ /** cancel index when putting values */
unsigned cancelidx;
/** the fields */
fields_t fields;
};
-
/**
* Put the 'car' into the 'buf'
* returns:
@@ -88,13 +102,13 @@ buf_put_car(
unsigned pos;
pos = buf->count;
- if (pos >= MAXBUFLEN)
+ if (pos >= MAX_BUFFER_LENGTH)
return -ECANCELED;
buf->count = pos + 1;
pos += buf->pos;
- if (pos >= MAXBUFLEN)
- pos -= MAXBUFLEN;
+ if (pos >= MAX_BUFFER_LENGTH)
+ pos -= MAX_BUFFER_LENGTH;
buf->content[pos] = car;
return 0;
}
@@ -116,30 +130,30 @@ buf_put_string(
remain = buf->count;
pos = buf->pos + remain;
- if (pos >= MAXBUFLEN)
- pos -= MAXBUFLEN;
- remain = MAXBUFLEN - remain;
+ if (pos >= MAX_BUFFER_LENGTH)
+ pos -= MAX_BUFFER_LENGTH;
+ remain = MAX_BUFFER_LENGTH - remain;
/* put all chars of the string */
while((c = *string++)) {
/* escape special characters */
- if (c == FS || c == RS || c == ESC) {
+ if (c == FIELD_SEPARATOR || c == RECORD_SEPARATOR || c == ESCAPE) {
if (!remain--)
goto cancel;
- buf->content[pos++] = ESC;
- if (pos == MAXBUFLEN)
+ buf->content[pos++] = ESCAPE;
+ if (pos == MAX_BUFFER_LENGTH)
pos = 0;
}
/* put the char */
if (!remain--)
goto cancel;
buf->content[pos++] = c;
- if (pos == MAXBUFLEN)
+ if (pos == MAX_BUFFER_LENGTH)
pos = 0;
}
/* record the new values */
- buf->count = MAXBUFLEN - remain;
+ buf->count = MAX_BUFFER_LENGTH - remain;
return 0;
cancel:
@@ -169,11 +183,11 @@ buf_write(
/* prepare the iovec */
vec[0].iov_base = buf->content + buf->pos;
- if (buf->pos + count <= MAXBUFLEN) {
+ if (buf->pos + count <= MAX_BUFFER_LENGTH) {
vec[0].iov_len = count;
n = 1;
} else {
- vec[0].iov_len = MAXBUFLEN - buf->pos;
+ vec[0].iov_len = MAX_BUFFER_LENGTH - buf->pos;
vec[1].iov_base = buf->content;
vec[1].iov_len = count - vec[0].iov_len;
n = 2;
@@ -191,14 +205,16 @@ buf_write(
/* update the state */
buf->count -= (unsigned)rc;
buf->pos += (unsigned)rc;
- if (buf->pos >= MAXBUFLEN)
- buf->pos -= MAXBUFLEN;
+ if (buf->pos >= MAX_BUFFER_LENGTH)
+ buf->pos -= MAX_BUFFER_LENGTH;
}
return (int)rc;
}
-/* get the 'fields' from 'buf' */
+/**
+ * get the 'fields' from 'buf'
+ */
static
void
buf_get_fields(
@@ -209,7 +225,7 @@ buf_get_fields(
unsigned read, write;
/* advance the pos after the end */
- assert(buf->content[buf->pos] == RS);
+ assert(buf->content[buf->pos] == RECORD_SEPARATOR);
buf->pos++;
/* init first field */
@@ -218,20 +234,20 @@ buf_get_fields(
for (;;) {
c = buf->content[read++];
switch(c) {
- case FS: /* field separator */
+ case FIELD_SEPARATOR: /* field separator */
buf->content[write++] = 0;
- if (fields->count >= MAXARGS)
+ if (fields->count >= MAX_FIELDS)
return;
fields->fields[++fields->count] = &buf->content[write];
break;
- case RS: /* end of line (record separator) */
+ case RECORD_SEPARATOR: /* end of line (record separator) */
buf->content[write] = 0;
fields->count += (write > 0);
return;
- case ESC: /* escaping */
+ case ESCAPE: /* escaping */
c = buf->content[read++];
- if (c != FS && c != RS && c != ESC)
- buf->content[write++] = ESC;
+ if (c != FIELD_SEPARATOR && c != RECORD_SEPARATOR && c != ESCAPE)
+ buf->content[write++] = ESCAPE;
buf->content[write++] = c;
break;
default: /* other characters */
@@ -254,10 +270,10 @@ buf_scan_end_record(
/* search the next RS */
while(buf->pos < buf->count) {
- if (buf->content[buf->pos] == RS) {
+ if (buf->content[buf->pos] == RECORD_SEPARATOR) {
/* check whether RS is escaped */
nesc = 0;
- while (buf->pos > nesc && buf->content[buf->pos - (nesc + 1)] == ESC)
+ while (buf->pos > nesc && buf->content[buf->pos - (nesc + 1)] == ESCAPE)
nesc++;
if ((nesc & 1) == 0)
return 1; /* not escaped */
@@ -267,7 +283,9 @@ buf_scan_end_record(
return 0;
}
-/** remove chars of 'buf' until pos */
+/**
+ * remove chars of 'buf' until pos
+ */
static
void
buf_crop(
@@ -279,7 +297,9 @@ buf_crop(
buf->pos = 0;
}
-/** read input 'buf' from 'fd' */
+/**
+ * read input 'buf' from 'fd'
+ */
static
int
inbuf_read(
@@ -289,11 +309,11 @@ inbuf_read(
ssize_t szr;
int rc;
- if (buf->count == MAXBUFLEN)
+ if (buf->count == MAX_BUFFER_LENGTH)
return -ENOBUFS;
do {
- szr = read(fd, buf->content + buf->count, MAXBUFLEN - buf->count);
+ szr = read(fd, buf->content + buf->count, MAX_BUFFER_LENGTH - buf->count);
} while(szr < 0 && errno == EINTR);
if (szr >= 0)
buf->count += (unsigned)(rc = (int)szr);
@@ -303,10 +323,7 @@ inbuf_read(
return rc;
}
-/**
- * create the prot structure in 'prot'
- * Return 0 in case of success or -ENOMEM in case of error
- */
+/* see prot.h */
int
prot_create(
prot_t **prot
@@ -325,9 +342,7 @@ prot_create(
return 0;
}
-/**
- * Destroys the protocol 'prot'
- */
+/* see prot.h */
void
prot_destroy(
prot_t *prot
@@ -335,9 +350,7 @@ prot_destroy(
free(prot);
}
-/**
- * reset the protocol 'prot'
- */
+/* see prot.h */
void
prot_reset(
prot_t *prot
@@ -349,6 +362,7 @@ prot_reset(
prot->fields.count = -1;
}
+/* see prot.h */
void
prot_put_cancel(
prot_t *prot
@@ -357,11 +371,12 @@ prot_put_cancel(
if (prot->outfields) {
count = prot->cancelidx - prot->outbuf.pos;
- prot->outbuf.count = count > MAXBUFLEN ? count - MAXBUFLEN : count;
+ prot->outbuf.count = count > MAX_BUFFER_LENGTH ? count - MAX_BUFFER_LENGTH : count;
prot->outfields = 0;
}
}
+/* see prot.h */
int
prot_put_end(
prot_t *prot
@@ -371,12 +386,13 @@ prot_put_end(
if (!prot->outfields)
rc = 0;
else {
- rc = buf_put_car(&prot->outbuf, RS);
+ rc = buf_put_car(&prot->outbuf, RECORD_SEPARATOR);
prot->outfields = 0;
}
return rc;
}
+/* see prot.h */
int
prot_put_field(
prot_t *prot,
@@ -385,7 +401,7 @@ prot_put_field(
int rc;
if (prot->outfields++)
- rc = buf_put_car(&prot->outbuf, FS);
+ rc = buf_put_car(&prot->outbuf, FIELD_SEPARATOR);
else {
prot->cancelidx = prot->outbuf.pos + prot->outbuf.count;
rc = 0;
@@ -396,6 +412,7 @@ prot_put_field(
return rc;
}
+/* see prot.h */
int
prot_put_fields(
prot_t *prot,
@@ -413,24 +430,16 @@ prot_put_fields(
return rc;
}
-/**
- * Put protocol encoded 'count' 'fields' to the output buffer
- * returns:
- * - 0 on success
- * - -EINVAL if the count of fields is too big
- * - -ECANCELED if there is not enough space in the buffer
- */
+/* see prot.h */
int
prot_put(
prot_t *prot,
unsigned count,
const char **fields
) {
- int rc = 0;
- unsigned index = 0;
+ int rc;
- while(!rc && index < count)
- rc = prot_put_field(prot, fields[index++]);
+ rc = prot_put_fields(prot, count, fields);
if (rc)
prot_put_cancel(prot);
else
@@ -445,6 +454,7 @@ prot_put(
* - -EINVAL if the count of fields is too big
* - -ECANCELED if there is not enought space in the buffer
*/
+/* see prot.h */
int
prot_putx(
prot_t *prot,
@@ -467,10 +477,7 @@ prot_putx(
return rc;
}
-/**
- * Check whether write should be done or not
- * Returns 1 if there is something to write or 0 otherwise
- */
+/* see prot.h */
int
prot_should_write(
prot_t *prot
@@ -478,13 +485,7 @@ prot_should_write(
return prot->outbuf.count > 0;
}
-/**
- * Write the content to write and return either the count
- * of bytes written or an error code (negative). Note that
- * the returned value tries to be the same as those returned
- * by "man 2 write". The only exception is -ENODATA that is
- * returned if there is nothing to be written.
- */
+/* see prot.h */
int
prot_write(
prot_t *prot,
@@ -493,13 +494,15 @@ prot_write(
return buf_write(&prot->outbuf, fdout);
}
+/* see prot.h */
int
prot_can_read(
prot_t *prot
) {
- return prot->inbuf.count < MAXBUFLEN;
+ return prot->inbuf.count < MAX_BUFFER_LENGTH;
}
+/* see prot.h */
int
prot_read(
prot_t *prot,
@@ -508,6 +511,7 @@ prot_read(
return inbuf_read(&prot->inbuf, fdin);
}
+/* see prot.h */
int
prot_get(
prot_t *prot,
@@ -523,6 +527,7 @@ prot_get(
return (int)prot->fields.count;
}
+/* see prot.h */
void
prot_next(
prot_t *prot
diff --git a/src/prot.h b/src/prot.h
index b961a37..a65c4b0 100644
--- a/src/prot.h
+++ b/src/prot.h
@@ -14,49 +14,84 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF THE PROTOCOL */
+/******************************************************************************/
+/******************************************************************************/
-struct prot;
typedef struct prot prot_t;
-#define MAXBUFLEN 2000
-#define MAXARGS 20
-#define FS ' '
-#define RS '\n'
-#define ESC '\\'
-
-
+/**
+ * Create the prot handler in 'prot'
+ *
+ * @param prot where to store the protocol handler
+ * @return 0 in case of success or -ENOMEM in case of error
+ */
extern
int
prot_create(
prot_t **prot
);
+/**
+ * Destroys the protocol handler 'prot'
+ *
+ * @param prot the protocol handler
+ */
+/**
+ *
+ */
extern
void
prot_destroy(
prot_t *prot
);
+/**
+ * Reset the protocol handler 'prot'
+ *
+ * @param prot the protocol handler
+ */
extern
void
prot_reset(
prot_t *prot
);
+/**
+ * Cancel any previous put not terminated with prot_put_end
+ *
+ * @param prot the protocol handler
+ */
extern
void
prot_put_cancel(
prot_t *prot
);
+/**
+ * Terminate a protocol record
+ *
+ * @param prot the protocol handler
+ * @return 0 on success
+ * -ECANCELED if the send buffer is full
+ */
extern
int
prot_put_end(
prot_t *prot
);
+/**
+ * Add a field to a protocol record
+ *
+ * @param prot the protocol handler
+ * @param field the field to add
+ * @return 0 on success
+ * -ECANCELED if the send buffer is full
+ */
extern
int
prot_put_field(
@@ -64,6 +99,15 @@ prot_put_field(
const char *field
);
+/**
+ * Add a set of fields to a protocol record
+ *
+ * @param prot the protocol handler
+ * @param count count of fields
+ * @param fields array of the fields to add
+ * @return 0 on success
+ * -ECANCELED if the send buffer is full
+ */
extern
int
prot_put_fields(
@@ -72,6 +116,15 @@ prot_put_fields(
const char **fields
);
+/**
+ * Add a set of fields to the record of protocol and terminate it
+ *
+ * @param prot the protocol handler
+ * @param count count of fields
+ * @param fields array of the fields to add
+ * @return 0 on success
+ * -ECANCELED if the send buffer is full
+ */
extern
int
prot_put(
@@ -80,6 +133,14 @@ prot_put(
const char **fields
);
+/**
+ * Add a variable length of items in protocol and terminate it
+ *
+ * @param prot the protocol handler
+ * @param ... a NULL terminated list of strings
+ * @return 0 on success
+ * -ECANCELED if the send buffer is full
+ */
extern
int
prot_putx(
@@ -87,12 +148,29 @@ prot_putx(
...
);
+/**
+ * Check whether write should be done or not
+ *
+ * @param prot the protocol handler
+ * @return 1 if there is something to write or 0 otherwise
+ */
extern
int
prot_should_write(
prot_t *prot
);
+/**
+ * Write the content to write and return either the count
+ * of bytes written or an error code (negative). Note that
+ * the returned value tries to be the same as those returned
+ * by "man 2 write". The only exception is -ENODATA that is
+ * returned if there is nothing to be written.
+ *
+ * @param prot the protocol handler
+ * @param fdout the file to write
+ * @return the count of bytes written or a negative -errno error code
+ */
extern
int
prot_write(
@@ -100,12 +178,25 @@ prot_write(
int fdout
);
+/**
+ * Is there space to receive data
+ *
+ * @param prot the protocol handler
+ * @return 0 if there is no space or 1 if read can be called
+ */
extern
int
prot_can_read(
prot_t *prot
);
+/**
+ * Read data from the input file fdin
+ *
+ * @param prot the protocol handler
+ * @param fdin the file to read
+ * @return the count of bytes read or a negative -errno error code
+ */
extern
int
prot_read(
@@ -113,6 +204,13 @@ prot_read(
int fdin
);
+/**
+ * Get the currently received fields and its count
+ *
+ * @param prot the protocol handler
+ * @param fields where to store the array of received fields (can be NULL)
+ * @return the count of fields or -EAGAIN if no field is available
+ */
extern
int
prot_get(
@@ -120,6 +218,12 @@ prot_get(
const char ***fields
);
+/**
+ * Forgive the current received fields so that the next call to prot_get
+ * returns the next received fields
+ *
+ * @param prot the protocol handler
+ */
extern
void
prot_next(
diff --git a/src/queue.c b/src/queue.c
index b02d7da..9d847da 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF QUEUE OF DATABASE MODIFIERS */
+/******************************************************************************/
+/******************************************************************************/
#include <stdint.h>
#include <stdbool.h>
@@ -32,7 +37,16 @@
*/
struct queue
{
- uint32_t read, write, capacity;
+ /** read index within queue */
+ uint32_t read;
+
+ /** write index within queue */
+ uint32_t write;
+
+ /** capacity of the queue */
+ uint32_t capacity;
+
+ /** the memory of the queue */
void *queue;
};
typedef struct queue queue_t;
@@ -40,6 +54,13 @@ typedef struct queue queue_t;
/** the queue */
static queue_t queue;
+/**
+ * Read data from the queue
+ *
+ * @param data where to store the data
+ * @param length length of the data to read
+ * @return true on success or false on error
+ */
static
bool
qread(
@@ -54,6 +75,12 @@ qread(
return true;
}
+/**
+ * Get a time from the queue
+ *
+ * @param value where to store the time
+ * @return true on success or false on error
+ */
static
bool
qget_time(
@@ -62,6 +89,12 @@ qget_time(
return qread(value, sizeof *value);
}
+/**
+ * Get a string from the queue
+ *
+ * @param text where to store the string
+ * @return true on success or false on error
+ */
static
bool
qget_string(
@@ -76,6 +109,13 @@ qget_string(
return true;
}
+/**
+ * Write the data to the queue
+ *
+ * @param data data to write
+ * @param length length of the data
+ * @return true on success or false on error
+ */
static
bool
qwrite(
@@ -100,6 +140,12 @@ qwrite(
return true;
}
+/**
+ * Put the time in the queue
+ *
+ * @param value the value to put
+ * @return true on success or false on error
+ */
static
bool
qput_time(
@@ -108,6 +154,13 @@ qput_time(
return qwrite(&value, sizeof value);
}
+/**
+ * Put the text in the queue
+ *
+ * @param text the text to put
+ *
+ * @return true on success or false on error
+ */
static
bool
qput_string(
@@ -115,13 +168,16 @@ qput_string(
) {
size_t len;
text = text ?: "";
+
/* check length */
len = strnlen(text, MAX_NAME_LENGTH + 1);
if (len > MAX_NAME_LENGTH)
return false;
+
return qwrite(text, 1 + (uint32_t)len);
}
+/* see queue.h */
int
queue_drop(
const data_key_t *key
@@ -130,10 +186,11 @@ queue_drop(
&& qput_string(key->session)
&& qput_string(key->user)
&& qput_string(key->permission)
- && qput_string(0)
+ && qput_string(NULL)
? 0 : -(errno = ENOMEM);
}
+/* see queue.h */
int
queue_set(
const data_key_t *key,
@@ -148,13 +205,14 @@ queue_set(
? 0 : -(errno = ENOMEM);
}
-
+/* see queue.h */
void
queue_clear(
) {
queue.write = 0;
}
+/* see queue.h */
int
queue_play(
) {
diff --git a/src/queue.h b/src/queue.h
index 7efc1f8..99aa9e2 100644
--- a/src/queue.h
+++ b/src/queue.h
@@ -14,14 +14,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF QUEUE OF DATABASE MODIFIERS */
+/******************************************************************************/
+/******************************************************************************/
-
+/**
+ * Queue droping the key
+ *
+ * @param key the key for dropping
+ * @return 0 on success or -ENOMEM on memory depletion
+ */
extern
int
queue_drop(
const data_key_t *key
);
+/**
+ * Queue setting of the key with the value
+ *
+ * @param key the key to set
+ * @param value the value to set to the key
+ * @return 0 on success or -ENOMEM on memory depletion
+ */
extern
int
queue_set(
@@ -29,14 +47,21 @@ queue_set(
const data_value_t *value
);
+/**
+ * Clear the content of the queue
+ */
extern
void
queue_clear(
);
+/**
+ * Play the content of the queue to alter the database accordingly to what
+ * is recorded
+ *
+ * @return 0 in case of success or a negative error code like -errno
+ */
extern
int
queue_play(
);
-
-
diff --git a/src/rcyn-client.c b/src/rcyn-client.c
index 2d9ca9b..e865888 100644
--- a/src/rcyn-client.c
+++ b/src/rcyn-client.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF CLIENT PART OF RCYN-PROTOCOL */
+/******************************************************************************/
+/******************************************************************************/
#include <stdbool.h>
#include <stdint.h>
diff --git a/src/rcyn-client.h b/src/rcyn-client.h
index f0fffe9..5128c85 100644
--- a/src/rcyn-client.h
+++ b/src/rcyn-client.h
@@ -14,9 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF CLIENT PART OF RCYN-PROTOCOL */
+/******************************************************************************/
+/******************************************************************************/
+
typedef struct rcyn rcyn_t;
typedef enum rcyn_type rcyn_type_t;
diff --git a/src/rcyn-protocol.c b/src/rcyn-protocol.c
index d570b04..09db418 100644
--- a/src/rcyn-protocol.c
+++ b/src/rcyn-protocol.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF COMMON PROTOCOL VALUES, CONSTANTS, PROCESSES */
+/******************************************************************************/
+/******************************************************************************/
#include <stdlib.h>
@@ -22,29 +27,26 @@
const char
_agent_[] = "agent",
_check_[] = "check",
+ _clear_[] = "clear",
+ _commit_[] = "commit",
+ _done_[] = "done",
_drop_[] = "drop",
_enter_[] = "enter",
+ _error_[] = "error",
_get_[] = "get",
+ _item_[] = "item",
_leave_[] = "leave",
_log_[] = "log",
- _rcyn_[] = "rcyn",
- _set_[] = "set",
- _test_[] = "test";
-
-const char
- _commit_[] = "commit",
- _rollback_[] = "rollback";
-
-const char
- _clear_[] = "clear",
- _done_[] = "done",
- _error_[] = "error",
- _item_[] = "item",
_no_[] = "no",
- _on_[] = "on",
_off_[] = "off",
+ _on_[] = "on",
+ _rcyn_[] = "rcyn",
+ _rollback_[] = "rollback",
+ _set_[] = "set",
+ _test_[] = "test",
_yes_[] = "yes";
+
#if !defined(RCYN_DEFAULT_SOCKET_SCHEME)
# define RCYN_DEFAULT_SOCKET_SCHEME "unix"
#endif
@@ -86,6 +88,7 @@ const char
rcyn_default_admin_socket_spec[] = RCYN_DEFAULT_ADMIN_SOCKET_SPEC,
rcyn_default_agent_socket_spec[] = RCYN_DEFAULT_AGENT_SOCKET_SPEC;
+/* see rcyn-protocol.h */
const char *
rcyn_get_socket_check(
const char *value
@@ -95,6 +98,7 @@ rcyn_get_socket_check(
?: rcyn_default_check_socket_spec;
}
+/* see rcyn-protocol.h */
const char *
rcyn_get_socket_admin(
const char *value
@@ -104,6 +108,7 @@ rcyn_get_socket_admin(
?: rcyn_default_admin_socket_spec;
}
+/* see rcyn-protocol.h */
const char *
rcyn_get_socket_agent(
const char *value
diff --git a/src/rcyn-protocol.h b/src/rcyn-protocol.h
index 8640186..553a3df 100644
--- a/src/rcyn-protocol.h
+++ b/src/rcyn-protocol.h
@@ -14,35 +14,37 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF COMMON PROTOCOL VALUES, CONSTANTS, PROCESSES */
+/******************************************************************************/
+/******************************************************************************/
+/* predefined protocol strings */
extern const char
_agent_[],
_check_[],
+ _clear_[],
+ _commit_[],
+ _done_[],
_drop_[],
_enter_[],
+ _error_[],
_get_[],
+ _item_[],
_leave_[],
_log_[],
- _rcyn_[],
- _set_[],
- _test_[];
-
-extern const char
- _commit_[],
- _rollback_[];
-
-extern const char
- _clear_[],
- _done_[],
- _error_[],
- _item_[],
_no_[],
_off_[],
_on_[],
+ _rcyn_[],
+ _rollback_[],
+ _set_[],
+ _test_[],
_yes_[];
+/* predefined names */
extern const char
rcyn_default_socket_scheme[],
rcyn_default_socket_dir[],
@@ -53,18 +55,36 @@ extern const char
rcyn_default_admin_socket_spec[],
rcyn_default_agent_socket_spec[];
+/**
+ * Get the socket specification for check usage
+ *
+ * @param value some value or NULL for getting default
+ * @return the socket specification for check usage
+ */
extern
const char *
rcyn_get_socket_check(
const char *value
);
+/**
+ * Get the socket specification for admin usage
+ *
+ * @param value some value or NULL for getting default
+ * @return the socket specification for admin usage
+ */
extern
const char *
rcyn_get_socket_admin(
const char *value
);
+/**
+ * Get the socket specification for agent usage
+ *
+ * @param value some value or NULL for getting default
+ * @return the socket specification for agent usage
+ */
extern
const char *
rcyn_get_socket_agent(
diff --git a/src/rcyn-server.c b/src/rcyn-server.c
index c6a0ef9..378a07d 100644
--- a/src/rcyn-server.c
+++ b/src/rcyn-server.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF SERVER PART OF RCYN-PROTOCOL */
+/******************************************************************************/
+/******************************************************************************/
#include <stdbool.h>
#include <stdint.h>
@@ -39,6 +44,8 @@
#include "socket.h"
#include "pollitem.h"
+#define MAX_PUTX_ITEMS 15
+
/** should log? */
bool
rcyn_server_log = 0;
@@ -177,7 +184,7 @@ putx(
client_t *cli,
...
) {
- const char *p, *fields[MAXARGS];
+ const char *p, *fields[MAX_PUTX_ITEMS];
unsigned n;
va_list l;
int rc;
@@ -187,7 +194,7 @@ putx(
va_start(l, cli);
p = va_arg(l, const char *);
while (p) {
- if (n == MAXARGS)
+ if (n == MAX_PUTX_ITEMS)
return -EINVAL;
fields[n++] = p;
p = va_arg(l, const char *);
@@ -421,7 +428,7 @@ onrequest(
key.session = args[2];
key.user = args[3];
key.permission = args[4];
- cyn_list(cli, getcb, &key);
+ cyn_list(getcb, cli, &key);
send_done(cli);
return;
}
diff --git a/src/rcyn-server.h b/src/rcyn-server.h
index 34cd46a..7982867 100644
--- a/src/rcyn-server.h
+++ b/src/rcyn-server.h
@@ -14,9 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF SERVER PART OF RCYN-PROTOCOL */
+/******************************************************************************/
+/******************************************************************************/
struct rcyn_server;
typedef struct rcyn_server rcyn_server_t;
diff --git a/src/socket.c b/src/socket.c
index fc01b8f..bd6b804 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -14,6 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF SOCKET OPENING FOLLOWING SPECIFICATION */
+/******************************************************************************/
+/******************************************************************************/
#include <stdlib.h>
#include <string.h>
@@ -33,7 +38,7 @@
#include "socket.h"
-#define BACKLOG 30
+#define BACKLOG 8
/******************************************************************************/
diff --git a/src/socket.h b/src/socket.h
index b5989e1..c0f9ddb 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -14,8 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#pragma once
+/******************************************************************************/
+/******************************************************************************/
+/* IMPLEMENTATION OF SOCKET OPENING FOLLOWING SPECIFICATION */
+/******************************************************************************/
+/******************************************************************************/
extern int socket_open(const char *uri, int server);