Add no-caching feature
authorJose Bollo <jose.bollo@iot.bzh>
Wed, 9 Oct 2019 16:40:39 +0000 (18:40 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Tue, 15 Oct 2019 20:06:24 +0000 (22:06 +0200)
Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
src/anydb.c
src/cache.c
src/cyn-server.c
src/cynagora.c
src/cynagora.h
src/dbinit.c
src/expire.c
src/expire.h
src/main-cynagoracli.c

index bfd2c09..ef41af7 100644 (file)
@@ -209,6 +209,8 @@ expired(
        time_t expire,
        time_t now
 ) {
+       if (expire < 0)
+               expire = -(expire + 1);
        return expire && expire <= now;
 }
 
index df346a8..d14e877 100644 (file)
@@ -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);
index 78143a4..8339d09 100644 (file)
@@ -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 */
index ee55dc6..4434d89 100644 (file)
@@ -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);
                }
        }
index d17476c..b77c0f4 100644 (file)
@@ -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;
 };
 
index e2366ad..67738f4 100644 (file)
@@ -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;
index 23ce6ae..2207d3c 100644 (file)
 /******************************************************************************/
 /******************************************************************************/
 
+#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)
index 1de82c2..4d996f8 100644 (file)
  *  - 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
 );
 
 /**
index db36243..af84760 100644 (file)
@@ -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)