*/
#include <stdlib.h>
+#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <string.h>
/**
* The cache structure is a blob of memory ('content')
* of 'count' bytes of only 'used' bytes.
- * That blob containts at sequence of records of variable length
+ * That blob contains at sequence of records of variable length
*/
struct cache
{
+ uint32_t cacheid;
uint32_t used;
uint32_t count;
uint8_t content[1];
void
cache_clear(
- cache_t *cache
+ cache_t *cache,
+ uint32_t cacheid
) {
- if (cache)
+ if (cache && (!cacheid || cache->cacheid != cacheid)) {
+ cache->cacheid = cacheid;
cache->used = 0;
+ }
}
int
return -ENOMEM;
nc->count = newsize;
- if (!c)
+ if (!c) {
+ nc->cacheid = 0;
nc->used = 0;
+ }
*cache = nc;
return 0;
}
extern
void
cache_clear(
- cache_t *cache
+ cache_t *cache,
+ uint32_t cacheid
);
extern
#include <assert.h>
#include <stdlib.h>
+#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
static struct callback *awaiters;
static struct callback *observers;
static struct agent *agents;
+static uint32_t last_changeid;
+static uint32_t last_changeid_string;
+static char changeid_string[12];
static
int
return 0;
}
+static
+void
+changed(
+) {
+ struct callback *c;
+
+ ++last_changeid;
+ for (c = observers; c ; c = c->next)
+ c->on_change_cb(c->closure);
+}
+
/** enter critical recoverable section */
int
cyn_enter(
bool commit
) {
int rc, rcp;
- struct callback *c, *e, **p;
+ struct callback *e, **p;
if (!magic)
return -EINVAL;
if (rc == 0) {
rcp = queue_play();
rc = db_transaction_end(rcp == 0) ?: rcp;
- if (rcp == 0) {
- for (c = observers; c ; c = c->next)
- c->on_change_cb(c->closure);
- }
+ if (rcp == 0)
+ changed();
}
}
queue_clear();
free(agent);
return 0;
}
+
+void
+cyn_changeid_reset(
+) {
+ last_changeid = 1;
+}
+
+uint32_t
+cyn_changeid(
+) {
+ return last_changeid;
+}
+
+extern
+const char *
+cyn_changeid_string(
+) {
+ if (last_changeid != last_changeid_string) {
+ last_changeid_string = last_changeid;
+ snprintf(changeid_string, sizeof changeid_string, "%u", last_changeid);
+ }
+ return changeid_string;
+}
\ No newline at end of file
const char *name
);
+extern
+void
+cyn_changeid_reset(
+);
+
+extern
+uint32_t
+cyn_changeid(
+);
+
+extern
+const char *
+cyn_changeid_string(
+);
rc = memdb_create(&memdb);
if (!rc) {
- rc = filedb_create(&filedb, directory, "CYNARA");
+ rc = filedb_create(&filedb, directory, NULL);
if (rc)
anydb_destroy(memdb);
}
#include "data.h"
#include "db.h"
+#include "cyn.h"
#include "rcyn-server.h"
#include "rcyn-protocol.h"
#include "dbinit.h"
cap_clear(caps);
rc = cap_set_proc(caps);
- /* initialize server */
- signal(SIGPIPE, SIG_IGN); /* avoid SIGPIPE! */
- rc = rcyn_server_create(&server, spec_socket_admin, spec_socket_check, spec_socket_agent);
- if (rc < 0) {
- fprintf(stderr, "can't initialise server: %m\n");
- return 1;
- }
-
/* connection to the database */
- rc = chdir(dbdir);
- if (rc < 0) {
- fprintf(stderr, "can not chroot to database directory %s: %m\n", dbdir);
- return 1;
- }
- rc = db_open(".");
+ rc = db_open(dbdir);
if (rc < 0) {
fprintf(stderr, "can not open database of directory %s: %m\n", dbdir);
return 1;
}
}
+ /* reset the change ids */
+ cyn_changeid_reset();
+
+ /* initialize server */
+ signal(SIGPIPE, SIG_IGN); /* avoid SIGPIPE! */
+ rc = rcyn_server_create(&server, spec_socket_admin, spec_socket_check, spec_socket_agent);
+ if (rc < 0) {
+ fprintf(stderr, "can't initialise server: %m\n");
+ return 1;
+ }
+
/* ready ! */
#if defined(WITH_SYSTEMD_ACTIVATION)
if (systemd)
get_reply(
rcyn_t *rcyn
) {
+ ;
int rc;
prot_next(rcyn->prot);
- rc = rcyn->reply.count = prot_get(rcyn->prot, &rcyn->reply.fields);
- if (rc <= 0)
- return rc;
- if (0 != strcmp(rcyn->reply.fields[0], _clear_)) {
- if (0 != strcmp(rcyn->reply.fields[0], _item_))
- rcyn->pending--;
- return rc;
+ rc = prot_get(rcyn->prot, &rcyn->reply.fields);
+ if (rc > 0) {
+ if (0 == strcmp(rcyn->reply.fields[0], _clear_)) {
+ cache_clear(rcyn->cache,
+ rc > 1 ? (uint32_t)atol(rcyn->reply.fields[1]) : 0);
+ rc = 0;
+ } else {
+ if (0 != strcmp(rcyn->reply.fields[0], _item_))
+ rcyn->pending--;
+ }
}
- cache_clear(rcyn->cache);
- return rcyn->reply.count = 0;
+ rcyn->reply.count = rc;
+ return rc;
}
static
/* init the client */
rcyn->pending = 0;
rcyn->reply.count = -1;
- cache_clear(rcyn->cache);
prot_reset(rcyn->prot);
rcyn->fd = socket_open(rcyn->socketspec, 0);
if (rcyn->fd < 0)
rc = wait_pending_reply(rcyn);
if (rc >= 0) {
rc = -EPROTO;
- if (rcyn->reply.count == 2
+ if (rcyn->reply.count >= 2
&& 0 == strcmp(rcyn->reply.fields[0], _yes_)
&& 0 == strcmp(rcyn->reply.fields[1], "1")) {
+ cache_clear(rcyn->cache,
+ rcyn->reply.count > 2 ? (uint32_t)atol(rcyn->reply.fields[2]) : 0);
rc = async(rcyn, EPOLL_CTL_ADD, EPOLLIN);
if (rc >= 0)
return 0;
return rc;
}
+void
+rcyn_disconnect(
+ rcyn_t *rcyn
+) {
+ disconnection(rcyn);
+}
+
void
rcyn_close(
rcyn_t *rcyn
rcyn_cache_clear(
rcyn_t *rcyn
) {
- cache_clear(rcyn->cache);
+ cache_clear(rcyn->cache, 0);
}
int
const char *socketspec
);
+extern
+void
+rcyn_disconnect(
+ rcyn_t *rcyn
+);
+
extern
void
rcyn_close(
hello:
c->s rcyn 1
- s->c yes 1
+ s->c yes 1 CACHEID
invalidate cache:
- s->c clear
+ s->c clear CACHEID
test a permission:
if (!cli->version) {
if (!ckarg(args[0], _rcyn_, 0) || count != 2 || !ckarg(args[1], "1", 0))
goto invalid;
- putx(cli, _yes_, "1", NULL);
+ putx(cli, _yes_, "1", cyn_changeid_string(), NULL);
flushw(cli);
cli->version = 1;
return;
client_t *cli = closure;
if (cli->checked) {
cli->checked = false;
- putx(cli, _clear_, NULL);
+ putx(cli, _clear_, cyn_changeid_string(), NULL);
flushw(cli);
}
}