summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJose Bollo <jose.bollo@iot.bzh>2019-10-09 18:40:39 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2019-10-15 22:06:24 +0200
commitb5fdd44014207c619b937e5c202ba27e77a2593c (patch)
tree37707b622fbf3a85d87436001c4a7cb196447067
parentd719343871969bd06f575b870d28296504433b55 (diff)
Add no-caching feature
Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
-rw-r--r--src/anydb.c2
-rw-r--r--src/cache.c2
-rw-r--r--src/cyn-server.c34
-rw-r--r--src/cynagora.c10
-rw-r--r--src/cynagora.h2
-rw-r--r--src/dbinit.c3
-rw-r--r--src/expire.c114
-rw-r--r--src/expire.h8
-rw-r--r--src/main-cynagoracli.c7
9 files changed, 141 insertions, 41 deletions
diff --git a/src/anydb.c b/src/anydb.c
index bfd2c09..ef41af7 100644
--- a/src/anydb.c
+++ b/src/anydb.c
@@ -209,6 +209,8 @@ expired(
time_t expire,
time_t now
) {
+ if (expire < 0)
+ expire = -(expire + 1);
return expire && expire <= now;
}
diff --git a/src/cache.c b/src/cache.c
index df346a8..d14e877 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -284,7 +284,7 @@ cache_put(
item_t *item;
size_t size;
- if (cache == NULL || value < -128 || value > 127)
+ if (cache == NULL || value < -128 || value > 127 || expire < 0)
return -EINVAL;
item = search(cache, key);
diff --git a/src/cyn-server.c b/src/cyn-server.c
index 78143a4..8339d09 100644
--- a/src/cyn-server.c
+++ b/src/cyn-server.c
@@ -272,7 +272,7 @@ entercb(
/** translate optional expire value */
static
const char *
-exp2txt(
+exp2check(
time_t expire,
char *buffer,
size_t bufsz
@@ -280,11 +280,37 @@ exp2txt(
if (!expire)
return NULL;
+ if (expire < 0)
+ return "-"; /* no cache */
+
/* TODO: check size */
snprintf(buffer, bufsz, "%lld", (long long)expire);
return buffer;
}
+/** translate optional expire value */
+static
+const char *
+exp2get(
+ time_t expire,
+ char *buffer,
+ size_t bufsz
+) {
+ if (!expire)
+ return NULL;
+
+ if (expire < 0) {
+ expire = -(expire + 1);
+ if (!expire)
+ return "-";
+ *buffer++ = '-';
+ bufsz--;
+ }
+
+ snprintf(buffer, bufsz, "%lld", (long long)expire);
+ return buffer;
+}
+
/** callback of checking */
static
void
@@ -299,7 +325,7 @@ testcheckcb(
if (!value) {
vtxt = _no_;
- etxt = 0;
+ etxt = NULL;
} else {
if (!strcmp(value->value, ALLOW))
vtxt = _yes_;
@@ -307,7 +333,7 @@ testcheckcb(
vtxt = _no_;
else
vtxt = _done_;
- etxt = exp2txt(value->expire, text, sizeof text);
+ etxt = exp2check(value->expire, text, sizeof text);
}
putx(cli, vtxt, etxt, NULL);
flushw(cli);
@@ -346,7 +372,7 @@ getcb(
char text[30];
putx(cli, _item_, key->client, key->session, key->user, key->permission,
- value->value, exp2txt(value->expire, text, sizeof text), NULL);
+ value->value, exp2get(value->expire, text, sizeof text), NULL);
}
/** handle a request */
diff --git a/src/cynagora.c b/src/cynagora.c
index ee55dc6..4434d89 100644
--- a/src/cynagora.c
+++ b/src/cynagora.c
@@ -363,10 +363,12 @@ status_check(
else
rc = -EPROTO;
- if (cynagora->reply.count >= 2)
- *expire = strtoll(cynagora->reply.fields[1], NULL, 10);
- else
+ if (cynagora->reply.count < 2)
*expire = 0;
+ else if (cynagora->reply.fields[1][0] == '-')
+ *expire = -1;
+ else
+ *expire = strtoll(cynagora->reply.fields[1], NULL, 10);
return rc;
}
@@ -553,7 +555,7 @@ check_or_test(
rc = wait_pending_reply(cynagora);
if (rc >= 0) {
rc = status_check(cynagora, &expire);
- if (rc >= 0 && action == _check_ && cynagora->cache)
+ if (rc >= 0 && action == _check_)
cache_put(cynagora->cache, key, rc, expire);
}
}
diff --git a/src/cynagora.h b/src/cynagora.h
index d17476c..b77c0f4 100644
--- a/src/cynagora.h
+++ b/src/cynagora.h
@@ -58,7 +58,7 @@ struct cynagora_key {
struct cynagora_value {
/** the associated value */
const char *value;
- /** the expiration */
+ /** the expiration in seconds since epoch, negative to avoid cache */
time_t expire;
};
diff --git a/src/dbinit.c b/src/dbinit.c
index e2366ad..67738f4 100644
--- a/src/dbinit.c
+++ b/src/dbinit.c
@@ -96,8 +96,7 @@ int dbinit_add_file(const char *path)
key.user = item[2];
key.permission = item[3];
value.value = item[4];
- value.expire = txt2exp(item[5]);
- if (value.expire < 0) {
+ if (!txt2exp(item[5], &value.expire)) {
fprintf(stderr, "bad expiration %s (%s:%d)\n", item[5], path, lino);
rc = -EINVAL;
goto error2;
diff --git a/src/expire.c b/src/expire.c
index 23ce6ae..2207d3c 100644
--- a/src/expire.c
+++ b/src/expire.c
@@ -20,9 +20,11 @@
/******************************************************************************/
/******************************************************************************/
+#include <stdbool.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
+#include <limits.h>
#include "expire.h"
@@ -31,52 +33,116 @@ 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 + 24*60*60/4;
+static const int YEAR = 365*24*60*60 + 24*60*60/4; /* average includes leap */
+static const time_t TMIN = (time_t)1 << ((CHAR_BIT * sizeof(time_t)) - 1);
+static const time_t TMAX = ~TMIN;
-/* see expire.h */
-time_t txt2exp(const char *txt)
+/** add positives x and y with saturation */
+static time_t pt_add(time_t x, time_t y)
{
- time_t r, x;
+ time_t r = x + y;
+ return r < 0 ? TMAX : r;
+}
- /* infinite time */
- if (!strcmp(txt, "always") || !strcmp(txt, "forever") || !strcmp(txt, "*"))
- return 0;
+/** multiply positive x by m with saturation */
+static time_t pt_mul(time_t x, int m)
+{
+ time_t r;
+
+ if (m <= 1)
+ r = 0;
+ else {
+ r = pt_mul(x, m >> 1) << 1;
+ if (r < 0)
+ r = TMAX;
+ }
+ return (m & 1) ? pt_add(r, x) : r;
+}
+
+/** multiply positive x by m and then add y with saturation */
+static time_t pt_muladd(time_t x, int m, time_t y)
+{
+ return pt_add(pt_mul(x, m), y);
+}
+
+/** multiply positive x by 10 and then add d with saturation */
+static time_t pt_tm10a(time_t x, int d)
+{
+ return pt_muladd(x, 10, (time_t)d);
+}
+
+/** translate the string 'txt' to its time representation */
+static bool parse_time_spec(const char *txt, time_t *time_out)
+{
+ time_t r, x;
/* parse */
- r = time(NULL);
+ r = 0;
while(*txt) {
x = 0;
while('0' <= *txt && *txt <= '9')
- x = (x << 3) + (x << 1) + (time_t)(*txt++ - '0');
+ x = pt_tm10a(x, *txt++ - '0');
switch(*txt) {
- case 'y': r += x * YEAR; txt++; break;
- case 'w': r += x * WEEK; txt++; break;
- case 'd': r += x * DAY; txt++; break;
- case 'h': r += x * HOUR; txt++; break;
- case 'm': r += x * MIN; txt++; break;
+ case 'y': r = pt_muladd(x, YEAR, r); txt++; break;
+ case 'w': r = pt_muladd(x, WEEK, r); txt++; break;
+ case 'd': r = pt_muladd(x, DAY, r); txt++; break;
+ case 'h': r = pt_muladd(x, HOUR, r); txt++; break;
+ case 'm': r = pt_muladd(x, MIN, r); txt++; break;
case 's': txt++; /*@fallthrough@*/
- case 0: r += x * SEC; break;
- default: return -1;
+ case 0: r = pt_muladd(x, SEC, r); break;
+ default: return false;
}
}
- return r;
+ *time_out = r;
+ return true;
+}
+
+
+/* see expire.h */
+bool txt2exp(const char *txt, time_t *time_out)
+{
+ bool nocache;
+ time_t r;
+
+ /* no cache */
+ nocache = txt[0] == '-';
+ txt += nocache;
+
+ /* infinite time */
+ if (!txt[0] || !strcmp(txt, "always") || !strcmp(txt, "forever") || !strcmp(txt, "*")) {
+ r = 0;
+ } else {
+ /* parse */
+ if (!parse_time_spec(txt, &r))
+ return false;
+ /* relative time */
+ r = pt_add(r, time(NULL));
+ }
+
+ *time_out = nocache ? -(r + 1) : r;
+ return true;
}
/* see expire.h */
size_t exp2txt(time_t expire, char *buffer, size_t buflen)
{
char b[100];
- size_t l;
- int n;
+ size_t l, n;
- if (!expire)
- strncpy(b, "forever", sizeof b);
- else {
+ n = 0;
+ if (expire < 0) {
+ b[n++] = '-';
+ b[n] = 0;
+ expire = -(expire + 1);
+ }
+ if (!expire) {
+ if (!n)
+ strncpy(b, "forever", sizeof b);
+ } else {
expire -= time(NULL);
- n = 0;
#define ADD(C,U) \
if (expire >= U) { \
- n += snprintf(&b[n], sizeof b - (size_t)n, "%lld" #C, (long long)(expire / U)); \
+ n += (size_t)snprintf(&b[n], sizeof b - (size_t)n, "%lld" #C, (long long)(expire / U)); \
expire %= U; \
}
ADD(y,YEAR)
diff --git a/src/expire.h b/src/expire.h
index 1de82c2..4d996f8 100644
--- a/src/expire.h
+++ b/src/expire.h
@@ -34,12 +34,14 @@
* - 2m2w means two months and 2 weeks
*
* @param txt the text to convert
- * @return the value for the text
+ * @param time_out where to store the result
+ * @return true if valid false otherwise
*/
extern
-time_t
+bool
txt2exp(
- const char *txt
+ const char *txt,
+ time_t *time_out
);
/**
diff --git a/src/main-cynagoracli.c b/src/main-cynagoracli.c
index db36243..af84760 100644
--- a/src/main-cynagoracli.c
+++ b/src/main-cynagoracli.c
@@ -334,9 +334,12 @@ int get_csupve(int ac, char **av, int *used, const char *def)
key.user = n > 3 ? av[3] : def;
key.permission = n > 4 ? av[4] : def;
value.value = n > 5 ? av[5] : "no";
- value.expire = n > 6 ? txt2exp(av[6]) : 0;
+ if (n <= 6)
+ value.expire = 0;
+ else if (!txt2exp(av[6], &value.expire))
+ return -EINVAL;
- return key.client && key.session && key.user && key.permission && value.value && value.expire >= 0 ? 0 : -EINVAL;
+ return key.client && key.session && key.user && key.permission && value.value ? 0 : -EINVAL;
}
int get_csup(int ac, char **av, int *used, const char *def)