PERFORCE change 123568 for review
Fredrik Lindberg
fli at FreeBSD.org
Mon Jul 16 01:12:58 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=123568
Change 123568 by fli at fli_nexus on 2007/07/16 01:12:45
- Revisit/fix record and resource construction, they now
properly follow the system state.
- Introduce a "pointer" concept where the resource data of
one record can point to name of another record. This useful
for PTR records that should follow a coresponding A/AAAA
record automatically.
- Add record probing and annoucing. When probing for a new
name a "probe context" is created to which records are
added, upon collision the record is removed from the context
which will self-destruct when no records are left.
A probe is initiated when ever a record changes name.
The "announce context" works in a similar way.
- Style fixes.
Affected files ...
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/dbrec.c#2 edit
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/dbrec.h#1 add
Differences ...
==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/dbrec.c#2 (text+ko) ====
@@ -26,14 +26,33 @@
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "mdnsd.h"
+#include "objalloc.h"
+#include "output.h"
#include "record.h"
#include "log.h"
#include "var.h"
static void record_type_del_cb(struct record_type *, void *);
+static void rec_update(struct dbr_rec *, struct vt_data *, size_t);
+static void rec_var_update(void *);
+static inline void rec_pastop(struct dbr_rec *);
+static void rec_del(struct dbr_rec *);
+static void res_update(struct dbr_res *, wchar_t **, size_t);
+static void res_var_update(void *);
+static void res_del(struct dbr_res *);
+
+static int dbr_pac_add(struct dbr_pac *, struct dbr_rec *, int);
+static int dbr_pac_del(struct dbr_rec *, int);
+static void dbr_pac_start(struct dbr_pac *, int, int, void *);
+static int probe_step(const struct event_tmr *, const ev_arg);
+static int an_step(const struct event_tmr *, const ev_arg);
+/*
+ * Initialize a database record system
+ */
void
dbr_init(struct dbr *dbr, void *context)
{
@@ -41,6 +60,7 @@
dbr->dbr_ctx = context;
MDNS_INIT_SET(dbr, dbr_magic);
+ hashtbl_init(&dbr->dbr_ident, 8, 512, 3);
var_init(&dbr->dbr_vars, mif->mif_glob->g_evl, dbr);
/* We only do the IN class */
@@ -58,6 +78,9 @@
dbr_del(dr);
}
+/*
+ * Destroy a database record system
+ */
void
dbr_destroy(struct dbr *dbr)
{
@@ -69,179 +92,211 @@
records_foreach(&dbr->dbr_recs, record_del_cb, NULL);
records_destroy(&dbr->dbr_recs);
var_destroy(&dbr->dbr_vars, mif->mif_glob->g_evl);
+ hashtbl_destroy(&dbr->dbr_ident);
MDNS_INIT_UNSET(dbr, dbr_magic);
+
dprintf(DEBUG_DBR, "Database records destroyed");
}
-static struct dbr_res *
-clone_res(struct dbr_res *orig)
+/*
+ * Clone a record
+ */
+static struct dbr_rec *
+clone_rec(struct dbr_rec *orig)
+{
+ struct dbr_rec *dr;
+
+ dr = malloc(sizeof(struct dbr_rec));
+ if (dr == NULL)
+ return (NULL);
+ memcpy(dr, orig, sizeof(struct dbr_rec));
+ dr->dr_flags |= DR_CLONE;
+ TAILQ_INSERT_TAIL(&orig->dr_clone.head, dr, dr_clone.next);
+ dprintf(DEBUG_DBR, "Database record cloned dr=%x, source=%x", dr, orig);
+ return (dr);
+}
+
+/*
+ * Clone all resources from `orig' onto `dr'
+ */
+static void
+clone_rec_res(struct dbr_rec *orig, struct dbr_rec *dr)
{
+ struct record *r;
+ struct record_type *rt;
+ struct record_res *rr;
struct dbr_res *ds;
+ struct dbr_rec *dr2;
+ void *res;
+ int ptr;
- ds = malloc(sizeof(struct dbr_res));
- if (ds == NULL)
- return (NULL);
- memcpy(ds, orig, sizeof(struct dbr_res));
- ds->ds_data = NULL;
- ds->ds_flags |= DS_CLONE;
- TAILQ_INSERT_TAIL(&orig->ds_clone.head, ds, ds_clone.next);
- dprintf(DEBUG_DBR, "Database resource cloned ds=%x, source=%x", ds, orig);
- return (ds);
+ MDNS_INIT_ASSERT(dr, dr_magic);
+ MDNS_INIT_ASSERT(orig, dr_magic);
+ r = &orig->dr_rec;
+ MDNS_INIT_ASSERT(r, r_magic);
+
+ record_foreach(rt, r) {
+ record_type_foreach(rr, rt) {
+ ds = record_res_getparent(rr);
+ ptr = ds->ds_flags & DS_POINTER;
+ if (ptr) {
+ dr2 = ds->ds_vdata.rec;
+ res = dr2->dr_ident;
+ }
+ else
+ res = ds->ds_vdata.wp;
+
+ dbr_res_add(dr, rt->rt_type, ds->ds_ttl, res, ptr);
+ }
+ }
+ dprintf(DEBUG_DBR, "Cloned resources from %x to %x", orig, dr);
}
/*
- * Variable update handler to resource data, will re-expand vaiables
- * and update affected resources.
- * This is an asynchronous callback routine which is called from the
- * variable event system.
+ * Update a database record
+ * dr - Database record
+ * vtd - Arrays of expanded names
+ * vtd_len - Array length
*
- * ptr - Opaque pointer passed to var_reg(), to this routine it's
- * always of type dbr_res {}
+ * A record clone will be created for each excessive member of `vtd', if
+ * there currently are more clones than the length of the provided array,
+ * then those clones are removed.
*/
static void
-res_var_update(void *ptr)
+rec_update(struct dbr_rec *dr, struct vt_data *vtd, size_t vtd_len)
{
- struct dbr_res *ds, *ds_clone, *ds_tmp;
- struct dbr_type *dt;
- struct dbr_rec *dr;
+ struct dbr_rec *dr_clone, *dr_tmp;
+ struct dbr_res *ds, *ds2;
struct dbr *dbr;
- struct record_type *rt;
- struct record_res *rr;
struct record *r;
- struct vt_data *vtd;
- size_t vtd_len, rlen;
uint32_t i;
int32_t diff;
- char *p;
+ wchar_t **names;
+ char *nam;
- ds = ptr;
- MDNS_INIT_ASSERT(ds, ds_magic);
- dt = ds->ds_type;
- MDNS_INIT_ASSERT(dt, dt_magic);
- dr = dt->dt_rec;
MDNS_INIT_ASSERT(dr, dr_magic);
dbr = dr->dr_dbr;
MDNS_INIT_ASSERT(dbr, dbr_magic);
- rt = &dt->dt_type;
+ assert(dr == dr->dr_chead);
- /* TODO: locking */
+ /* Stop pending probes/announces */
+ rec_pastop(dr);
- vtd = var_expand(&dbr->dbr_vars, ds->ds_vdata, &vtd_len);
+ /*
+ * If the provided array length is 0 there are no available
+ * names, invalidate record and remove all clones.
+ */
+ if (vtd_len == 0) {
+ if (dr->dr_name != NULL)
+ free(dr->dr_name);
+ dr->dr_name = NULL;
+ dr->dr_flags |= DR_INVALID;
+ dr->dr_flags &= ~DR_OK;
- if (vtd_len == 0) {
- if (!(ds->ds_flags & DS_INVALID)) {
- /* TODO: annonuce old res with ttl 0 */
- free(ds->ds_data);
+ TAILQ_FOREACH_SAFE(dr_clone, &dr->dr_clone.head,
+ dr_clone.next, dr_tmp) {
+ rec_del(dr_clone);
}
- record_res_setdata(&ds->ds_res, NULL, 0);
- ds->ds_flags |= DS_INVALID;
- dprintf(DEBUG_DBR, "Removing clones on %x, clones=%d",
- ds, ds->ds_clones);
- TAILQ_FOREACH(ds_clone, &ds->ds_clone.head, ds_clone.next) {
- TAILQ_REMOVE(&ds->ds_clone.head, ds_clone, ds_clone.next);
- record_res_del(&ds_clone->ds_res);
+
+ /*
+ * Invalidate all database resources that are using this
+ * record name as their data source.
+ */
+ TAILQ_FOREACH(ds, &dr->dr_res_ptr, ds_ptr_next) {
+ ds->ds_flags |= DS_INVALID;
free(ds->ds_data);
- free(ds_clone);
- ds->ds_clones--;
+ ds->ds_data = NULL;
}
- goto out;
+ return;
+ }
+
+ i = 1;
+ nam = mdns_name_encode(vtd[0].vtd_str, vtd[0].vtd_len, MDNS_ENC_AUTO);
+ r = &dr->dr_rec;
+ if (dr->dr_name != NULL)
+ free(dr->dr_name);
+ record_setname(r, nam);
+
+ free(nam);
+ dr->dr_name = vtd[0].vtd_str;
+ dr->dr_flags &= ~(DR_OK | DR_INVALID);
+
+ /*
+ * Replace names as long as there are enough clones
+ * and results available.
+ */
+ TAILQ_FOREACH(dr_clone, &dr->dr_clone.head, dr_clone.next) {
+ if ((i - 1) == dr->dr_clones || i == vtd_len)
+ break;
+ r = &dr_clone->dr_rec;
+ nam = mdns_name_encode(vtd[i].vtd_str, vtd[i].vtd_len,
+ MDNS_ENC_AUTO);
+ record_setname(r, nam);
+ free(nam);
+ if (dr_clone->dr_name != NULL)
+ free(dr_clone->dr_name);
+ dr_clone->dr_name = vtd[i].vtd_str;
+ dr_clone->dr_flags &= ~DR_OK;
+ i++;
}
- else if (vtd_len >= 1) {
- if (!(ds->ds_flags & DS_INVALID))
- free(ds->ds_data);
- ds->ds_data = vtd[0].vtd_str;
- p = mdns_res_encode(mdns_c_in, rt->rt_type, ds->ds_data,
- MDNS_ENC_WCHAR, vtd[0].vtd_len, &rlen);
- record_res_setdata(&ds->ds_res, p, rlen);
- i = 1;
- /*
- * Replace resource data as long as there is enough clones
- * and results available.
- */
- TAILQ_FOREACH(ds_clone, &ds->ds_clone.head, ds_clone.next) {
- if (i == ds->ds_clones || i == vtd_len)
- break;
- free(ds_clone->ds_data);
- ds->ds_data = vtd[i].vtd_str;
- p = mdns_res_encode(mdns_c_in, rt->rt_type, ds->ds_data,
- MDNS_ENC_WCHAR, vtd[i].vtd_len, &rlen);
- record_res_setdata(&ds->ds_res, p, rlen);
+ /* More results than clones, expand */
+ if (vtd_len > i) {
+ diff = vtd_len - i;
+ while (diff-- > 0) {
+ dr_clone = clone_rec(dr);
+ dr_clone->dr_clones = 0;
+ dr->dr_clones++;
+ r = &dr_clone->dr_rec;
+ nam = mdns_name_encode(vtd[i].vtd_str, vtd[i].vtd_len,
+ MDNS_ENC_AUTO);
+ record_get(&dbr->dbr_recs, &r, RECORD_NOALLOC, nam);
+ record_setparent(r, dr_clone);
+ clone_rec_res(dr, dr_clone);
+ free(nam);
+ dr_clone->dr_name = vtd[i].vtd_str;
i++;
}
+ }
+ /* More clones than results, shrink */
+ else if (dr->dr_clones >= i) {
+ diff = dr->dr_clones - i;
+ while (diff-- >= 0) {
+ dr_tmp = TAILQ_LAST(&dr->dr_clone.head, recclone_head);
+ rec_del(dr_tmp);
+ }
+ }
- /* More results than clones, expand */
- if (vtd_len > i) {
- diff = vtd_len - i;
- r = ds->ds_res.rr_type->rt_record;
- MDNS_INIT_ASSERT(r, r_magic);
- while (diff-- > 0) {
- ds_clone = clone_res(ds);
- ds_clone->ds_clones = 0;
- ds->ds_clones++;
- ds_clone->ds_data = vtd[i].vtd_str;
- rr = &ds_clone->ds_res;
- p = mdns_res_encode(mdns_c_in, rt->rt_type, ds_clone->ds_data,
- MDNS_ENC_WCHAR, vtd[i].vtd_len, &rlen);
- record_res_add(r, &rr, RECORD_NOALLOC, rt->rt_type, p, rlen);
- record_res_setparent(&ds_clone->ds_res, ds);
- i++;
- }
- }
- /* More clones than results, shrink */
- else if (ds->ds_clones >= i) {
- diff = ds->ds_clones - i;
- while (diff-- >= 0) {
- ds_tmp = TAILQ_LAST(&ds->ds_clone.head, clone_head);
- TAILQ_REMOVE(&ds->ds_clone.head, ds_tmp, ds_clone.next);
- record_res_del(&ds_tmp->ds_res);
- free(ds_tmp);
- ds->ds_clones--;
- }
- }
+ /* Update resources that points to this record */
+ names = malloc(sizeof(wchar_t *) * vtd_len);
+ TAILQ_FOREACH_SAFE(ds, &dr->dr_res_ptr, ds_ptr_next, ds2) {
+ for (i = 0; i < vtd_len; i++)
+ names[i] = _wcsdup(vtd[i].vtd_str);
+ res_update(ds, names, vtd_len);
}
+ free(names);
- ds->ds_flags &= ~DS_INVALID;
- /* TODO: cache flush annonuce */
- free(vtd);
dprintf(DEBUG_DBR,
- "Database resource %x updated, type=%d, ttl=%d, clones=%d",
- ds, rt->rt_type, ds->ds_ttl, vtd_len-1);
- return;
-out:
- var_vtdfree(vtd, vtd_len);
- dprintf(DEBUG_DBR, "Database resource %x marked as invalid", ds);
+ "Database record r=%x, (%ls) updated, flags=%x, clones=%d",
+ dr, dr->dr_names[dr->dr_cur], dr->dr_flags, dr->dr_clones);
}
-static struct dbr_rec *
-clone_rec(struct dbr_rec *orig)
-{
- struct dbr_rec *dr;
-
- dr = malloc(sizeof(struct dbr_rec));
- if (dr == NULL)
- return (NULL);
- memcpy(dr, orig, sizeof(struct dbr_rec));
- dr->dr_flags |= DR_CLONE;
- TAILQ_INSERT_TAIL(&orig->dr_clone.head, dr, dr_clone.next);
- dprintf(DEBUG_DBR, "Database record cloned dr=%x, source=%x", dr, orig);
- return (dr);
-}
-
-
+/*
+ * Variable update handler to record names, callback routine from
+ * variable system.
+ */
static void
rec_var_update(void *ptr)
{
- struct dbr_rec *dr, *dr_clone, *dr_tmp;
struct dbr *dbr;
+ struct dbr_rec *dr, *dr2;
+ struct dbr_pac *pac;
+ struct dbr_res *ds;
struct record *r;
struct vt_data *vtd;
size_t vtd_len;
wchar_t *wp;
- char *nam;
- uint32_t i;
- int32_t diff;
dr = ptr;
MDNS_INIT_ASSERT(dr, dr_magic);
@@ -249,91 +304,58 @@
MDNS_INIT_ASSERT(dbr, dbr_magic);
r = &dr->dr_rec;
+ assert(dr == dr->dr_chead);
+
wp = dr->dr_names[dr->dr_cur];
vtd = var_expand(&dbr->dbr_vars, wp, &vtd_len);
- if (vtd_len >= 1) {
- nam = mdns_name_encode(vtd[0].vtd_str, vtd[0].vtd_len,
- MDNS_ENC_AUTO);
- record_setname(r, nam);
- free(nam);
- i = 1;
+ rec_update(dr, vtd, vtd_len);
+ free(vtd);
- /*
- * Replace names as long as there are enough clones
- * and results available.
- */
- TAILQ_FOREACH(dr_clone, &dr->dr_clone.head, dr_clone.next) {
- if (i == dr->dr_clones || i == vtd_len)
- break;
- nam = mdns_name_encode(vtd[i].vtd_str, vtd[i].vtd_len,
- MDNS_ENC_AUTO);
- record_setname(r, nam);
- free(nam);
- i++;
- }
-
- /* More results than clones, expand */
- if (vtd_len > i) {
- diff = vtd_len - i;
- while (diff-- > 0) {
- dr_clone = clone_rec(dr);
- dr_clone->dr_clones = 0;
- dr->dr_clones++;
- r = &dr_clone->dr_rec;
- nam = mdns_name_encode(vtd[i].vtd_str, vtd[i].vtd_len,
- MDNS_ENC_AUTO);
- record_get(&dbr->dbr_recs, &r, RECORD_NOALLOC, nam);
- record_setparent(r, dr_clone);
-// FIXME clone all resource data
- free(nam);
- i++;
- }
- }
- /* More clones than results, shrink */
- else if (dr->dr_clones >= i) {
- diff = dr->dr_clones - i;
- while (diff-- >= 0) {
- dr_tmp = TAILQ_LAST(&dr->dr_clone.head, recclone_head);
- TAILQ_REMOVE(&dr->dr_clone.head, dr_tmp, dr_clone.next);
- r = &dr_tmp->dr_rec;
- record_foreach_type(r, record_type_del_cb, NULL);
- record_release(r);
- MDNS_INIT_UNSET(dr_tmp, dr_magic);
- free(dr_tmp);
- dr->dr_clones--;
- }
- }
-
- if (dr->dr_type == DR_SHARED)
- dr->dr_state = DR_OK;
- else {
- dr->dr_state = DR_TENTATIVE;
- /* TODO: relaunch probe */
- }
+ /*
+ * Create a probe context and and affected records to it
+ */
+ pac = dbr_pac_new(dbr, PAC_PROBE);
+ dbr_probe_add(pac, dr);
+ TAILQ_FOREACH(dr2, &dr->dr_clone.head, dr_clone.next) {
+ dbr_probe_add(pac, dr2);
}
- else {
- dr->dr_state = DR_INVALID;
+ /* Resources pointing to this record */
+ TAILQ_FOREACH(ds, &dr->dr_res_ptr, ds_ptr_next) {
+ MDNS_INIT_ASSERT(ds, ds_magic);
+ dr2 = ds->ds_type->dt_rec;
+ MDNS_INIT_ASSERT(dr2, dr_magic);
+ dbr_probe_add(pac, dr2);
}
-
- if (vtd != NULL)
- var_vtdfree(vtd, vtd_len);
-
- dprintf(DEBUG_DBR,
- "Database record r=%x updated name=%ls, state=%d, clones=%d",
- dr, wp, dr->dr_state, dr->dr_clones);
+ dbr_probe_start(pac);
}
+/*
+ * Add a new database record
+ * dbr - Record database
+ * ident - Unique record set identifier
+ * names - Array of un-expanded alternativ names (NULL-terminated)
+ * shared - Shared record?
+ *
+ */
struct dbr_rec *
-dbr_add(struct dbr *dbr, wchar_t **names, int type)
+dbr_add(struct dbr *dbr, char *ident, wchar_t **names, int shared)
{
wchar_t *wp;
struct vt_data *vtd;
size_t vtd_len;
- struct dbr_rec *dr, *dr_clone;
+ struct dbr_rec *dr;
struct record *r;
- char *nam;
int error;
- uint32_t i, j;
+ uint32_t i;
+
+ dr = hashtbl_find(&dbr->dbr_ident, ident, strlen(ident));
+ if (dr != NULL) {
+ dprintf(DEBUG_DBR, "Record set %s does already exists dr=%x",
+ ident, dr);
+ return (dr);
+ }
+ else if (names[0] == NULL)
+ return (NULL);
i = 0;
error = -1;
@@ -341,78 +363,61 @@
TAILQ_INIT(&dr->dr_clone.head);
dr->dr_clones = 0;
dr->dr_dbr = dbr;
+ dr->dr_name = NULL;
+ dr->dr_ident = strdup(ident);
dr->dr_names = names;
- dr->dr_type = type;
dr->dr_cur = 0;
+ dr->dr_cols = 0;
+ dr->dr_col_ts = 0;
dr->dr_chead = dr;
+ dr->dr_flags = DR_INVALID;
+ r = &dr->dr_rec;
+ record_get(&dbr->dbr_recs, &r, RECORD_NOALLOC, ident);
+ record_setparent(r, dr);
+
+ if (shared)
+ dr->dr_flags |= DR_SHARED;
+ TAILQ_INIT(&dr->dr_res_ptr);
MDNS_INIT_SET(dr, dr_magic);
- r = &dr->dr_rec;
+
do {
wp = names[i++];
if (wp == NULL)
break;
vtd = var_expand(&dbr->dbr_vars, wp, &vtd_len);
- if (vtd_len >= 1) {
- nam = mdns_name_encode(vtd[0].vtd_str, vtd[0].vtd_len,
- MDNS_ENC_AUTO);
- record_get(&dbr->dbr_recs, &r, RECORD_NOALLOC, nam);
- record_setparent(r, dr);
- free(nam);
- }
- error = var_reg(&dbr->dbr_vars, wp, rec_var_update, dr);
- if (error != 0) {
- dprintf(DEBUG_DBR, "Variable registration failed");
- var_dereg(&dbr->dbr_vars, wp, dr);
- if (vtd_len >= 1)
- record_release(r);
+ if (vtd_len > 0) {
+ var_reg(&dbr->dbr_vars, wp, rec_var_update, dr);
+ rec_update(dr, vtd, vtd_len);
}
else {
- dr->dr_cur = i - 1;
- for (j = 1; j < vtd_len; j++) {
- nam = mdns_name_encode(vtd[j].vtd_str, vtd[j].vtd_len,
- MDNS_ENC_AUTO);
- dr_clone = clone_rec(dr);
- dr->dr_clones++;
- dr_clone->dr_chead = dr;
- r = &dr_clone->dr_rec;
- record_get(&dbr->dbr_recs, &r, RECORD_NOALLOC, nam);
- record_setparent(r, dr_clone);
- free(nam);
- }
+ var_vtdfree(vtd, vtd_len);
}
+ } while (vtd_len == 0);
- var_vtdfree(vtd, vtd_len);
- } while (error != 0);
-
/*
* If all alternative names fail to expand just set it to the
* first name and mark the record as invalid.
*/
- if (error != 0) {
+ if (vtd_len == 0) {
wp = names[0];
var_reg(&dbr->dbr_vars, wp, rec_var_update, dr);
- dr->dr_state = DR_INVALID;
dr->dr_cur = 0;
-
- /*
- * This is slightly "incorrect" as we add the unexpanded
- * name to the record database, but if we do not add it
- * we can't add any resources to this record.
- */
- nam = mdns_name_encode(wp, wcslen(wp), MDNS_ENC_WCHAR);
- record_get(&dbr->dbr_recs, &r, RECORD_NOALLOC, nam);
- record_setparent(&dr->dr_rec, r);
}
else {
- dr->dr_state = DR_TENTATIVE;
+ dr->dr_cur = i - 1;
}
- if (type == DR_SHARED && dr->dr_state == DR_TENTATIVE)
- dr->dr_state = DR_OK;
+ dr->dr_flags &= ~DR_OK;
+ hashtbl_add(&dbr->dbr_ident, dr->dr_ident, strlen(dr->dr_ident), dr, 0);
+
+ if ((dr->dr_flags & DR_SHARED) && !(dr->dr_flags & DR_INVALID))
+ dr->dr_flags |= DR_OK;
- dprintf(DEBUG_DBR, "New database record dr=%x, name=%ls, clones=%d",
- dr, dr->dr_names[dr->dr_cur], dr->dr_clones);
+ dprintf(DEBUG_DBR,
+ "New database record ident=%s, dr=%x, name=%ls, clones=%d, "
+ "flags=%x", dr->dr_ident, dr, dr->dr_names[dr->dr_cur],
+ dr->dr_clones, dr->dr_flags);
return (dr);
}
@@ -434,20 +439,68 @@
MDNS_INIT_ASSERT(rt, rt_magic);
dt = record_type_getparent(rt);
-
record_type_foreach_res(rt, record_res_del_cb, NULL);
assert(record_type_refcnt(rt) == 0);
free(dt);
}
+/*
+ * Free a database record and resources allocated to it
+ * dr - Database record
+ */
+static void
+rec_del(struct dbr_rec *dr)
+{
+ struct dbr_rec *drh;
+ struct record *r;
+ wchar_t *wp;
+ int i;
+
+ MDNS_INIT_ASSERT(dr, dr_magic);
+ r = &dr->dr_rec;
+ drh = dr->dr_chead;
+ MDNS_INIT_ASSERT(drh, dr_magic);
+
+ if (dr->dr_flags & DR_PROBING)
+ dbr_probe_del(dr);
+ if (dr->dr_flags & DR_ANNOUNCE)
+ dbr_an_del(dr);
+
+ if (dr->dr_flags & DR_CLONE) {
+ TAILQ_REMOVE(&drh->dr_clone.head, dr, dr_clone.next);
+ drh->dr_clones--;
+ }
+ else {
+ i = 0;
+ do {
+ wp = dr->dr_names[i++];
+ if (wp != NULL)
+ free(wp);
+ } while(wp != NULL);
+ free(dr->dr_names);
+ free(dr->dr_ident);
+ }
+
+ record_foreach_type(r, record_type_del_cb, NULL);
+ record_release(r);
+ assert(record_refcnt(r) == 0);
+ if (!(dr->dr_flags & DR_INVALID))
+ free(dr->dr_name);
+ MDNS_INIT_UNSET(dr, dr_magic);
+ free(dr);
+}
+
+/*
+ * Remove a database record, any existing clones and also removes
+ * resources that are using this record name as their resource data.
+ * dr - Database record
+ */
void
dbr_del(struct dbr_rec *dr)
{
- struct record *r;
struct dbr *dbr;
struct dbr_rec *dr2, *dr_tmp;
- int i;
- wchar_t *wp;
+ struct dbr_res *ds, *ds2;
MDNS_INIT_ASSERT(dr, dr_magic);
dbr = dr->dr_dbr;
@@ -455,58 +508,253 @@
dr = dr->dr_chead;
var_dereg(&dbr->dbr_vars, dr->dr_names[dr->dr_cur], dr);
+ /*
+ * Remove any resources that are using this records name
+ * as their resource data.
+ */
+ TAILQ_FOREACH_SAFE(ds, &dr->dr_res_ptr, ds_ptr_next, ds2)
+ dbr_res_del(ds);
TAILQ_FOREACH_SAFE(dr2, &dr->dr_clone.head, dr_clone.next, dr_tmp) {
- /* TODO: clear ouput queue */
- MDNS_INIT_ASSERT(dr2, dr_magic);
- r = &dr2->dr_rec;
- TAILQ_REMOVE(&dr->dr_clone.head, dr2, dr_clone.next);
- dr->dr_clones--;
- dprintf(DEBUG_DBR, "Removing record clone dr=%x, orig=%x", dr2, dr);
- record_foreach_type(r, record_type_del_cb, NULL);
- record_release(r);
- assert(record_refcnt(r) == 0);
- MDNS_INIT_UNSET(dr2, dr_magic);
- free(dr2);
+ rec_del(dr2);
+ }
+ rec_del(dr);
+ dprintf(DEBUG_DBR, "Removed record dr=%x", dr);
+}
+
+/*
+ * Clone a resource
+ */
+static struct dbr_res *
+clone_res(struct dbr_res *orig)
+{
+ struct dbr_res *ds;
+
+ ds = malloc(sizeof(struct dbr_res));
+ if (ds == NULL)
+ return (NULL);
+ memcpy(ds, orig, sizeof(struct dbr_res));
+ ds->ds_data = NULL;
+ ds->ds_flags |= DS_CLONE | DS_INVALID;
+ ds->ds_time.tv_nsec = ds->ds_time.tv_sec = 0;
+ TAILQ_INSERT_TAIL(&orig->ds_clone.head, ds, ds_clone.next);
+ dprintf(DEBUG_DBR, "Database resource cloned ds=%x, source=%x",
+ ds, orig);
+ return (ds);
+}
+
+/*
+ * Update a resource with new data
+ */
+static void
+res_update(struct dbr_res *ds, wchar_t **res, size_t reslen)
+{
+ struct dbr_rec *dr;
+ struct dbr_type *dt;
+ struct dbr_res *ds_clone, *ds_tmp;
+ struct record *r;
+ struct record_type *rt;
+ struct record_res *rr;
+ char *p;
+ size_t rlen;
+ int32_t diff;
+ uint32_t i;
+
+ MDNS_INIT_ASSERT(ds, ds_magic);
+ dt = ds->ds_type;
+ MDNS_INIT_ASSERT(dt, dt_magic);
+ dr = dt->dt_rec;
+ MDNS_INIT_ASSERT(dr, dr_magic);
+ rt = &dt->dt_type;
+ rr = &ds->ds_res;
+ r = rt->rt_record;
+
+ assert(ds == ds->ds_chead);
+
+ /*
+ * If there are no resources available in the provided array,
+ * invalidate the record and remove existing clones.
+ */
+ if (reslen == 0) {
+ if (ds->ds_data != NULL)
+ free(ds->ds_data);
+ record_res_setdata(&ds->ds_res, NULL, 0);
+ ds->ds_data = NULL;
+ ds->ds_flags |= DS_INVALID;
+
+ TAILQ_FOREACH_SAFE(ds_clone, &ds->ds_clone.head,
+ ds_clone.next, ds_tmp) {
+ res_del(ds_clone);
+ }
+ return;
+ }
+
+ i = 1;
+ p = mdns_res_encode(mdns_c_in, rt->rt_type, res[0],
+ MDNS_ENC_WCHAR, wcslen(res[0]), &rlen);
+ if (ds->ds_data != NULL)
+ free(ds->ds_data);
+ record_res_setdata(&ds->ds_res, p, rlen);
+ ds->ds_flags &= ~DS_INVALID;
+ ds->ds_data = res[0];
+
+ /*
+ * Replace resource data as long as there is enough clones
+ * and results available.
+ */
+ TAILQ_FOREACH(ds_clone, &ds->ds_clone.head, ds_clone.next) {
+ if ((i - 1) == ds->ds_clones || i == reslen)
+ break;
+ if (!(ds_clone->ds_flags & DS_INVALID))
+ free(ds_clone->ds_data);
+ ds_clone->ds_data = res[i];
+ p = mdns_res_encode(mdns_c_in, rt->rt_type, res[i],
+ MDNS_ENC_WCHAR, wcslen(res[i]), &rlen);
+ record_res_setdata(&ds_clone->ds_res, p, rlen);
+ ds_clone->ds_flags &= ~DS_INVALID;
+ i++;
+ }
+
+ /* More results than clones, expand */
+ if (reslen > i) {
+ diff = reslen - i;
+ r = ds->ds_res.rr_type->rt_record;
+ MDNS_INIT_ASSERT(r, r_magic);
+ while (diff-- > 0) {
+ ds_clone = clone_res(ds);
+ ds_clone->ds_clones = 0;
+ ds->ds_clones++;
+ ds_clone->ds_data = res[i];
+ rr = &ds_clone->ds_res;
+ p = mdns_res_encode(mdns_c_in, rt->rt_type,
+ res[i], MDNS_ENC_WCHAR, wcslen(res[i]), &rlen);
+ record_res_add(r, &rr, RECORD_NOALLOC, rt->rt_type,
+ p, rlen);
+ record_res_setparent(&ds_clone->ds_res, ds);
+ i++;
+ ds_clone->ds_flags &= ~DS_INVALID;
+ }
+ }
+ /* More clones than results, shrink */
+ else if (ds->ds_clones >= i) {
+ diff = ds->ds_clones - i;
+ while (diff-- >= 0) {
+ ds_tmp = TAILQ_LAST(&ds->ds_clone.head, clone_head);
+ res_del(ds_tmp);
+ }
}
- r = &dr->dr_rec;
- record_foreach_type(r, record_type_del_cb, NULL);
- record_release(r);
- assert(record_refcnt(r) == 0);
- i = 0;
- do {
- wp = dr->dr_names[i++];
- if (wp != NULL)
- free(wp);
- } while(wp != NULL);
- free(dr->dr_names);
- MDNS_INIT_UNSET(dr, dr_magic);
- free(dr);
- dprintf(DEBUG_DBR, "Removed record dr=%x", dr);
+ dprintf(DEBUG_DBR, "Resource ds=%x updated, clones=%d",
+ ds, ds->ds_clones);
}
+/*
+ * Variable update handler to resource data, will re-expand vaiables
+ * and update affected resources.
+ * This is an asynchronous callback routine which is called from the
+ * variable event system.
+ *
+ * ptr - Opaque pointer passed to var_reg(), to this routine it's
+ * always of type dbr_res {}
+ */
+static void
+res_var_update(void *ptr)
+{
+ struct dbr *dbr;
+ struct dbr_rec *dr;
+ struct dbr_type *dt;
+ struct dbr_res *ds;
+ struct dbr_pac *pac;
+ struct vt_data *vtd;
+ size_t vtd_len;
+ uint32_t i;
+ wchar_t **names;
+
+ ds = ptr;
+ MDNS_INIT_ASSERT(ds, ds_magic);
+ dt = ds->ds_type;
+ MDNS_INIT_ASSERT(dt, dt_magic);
+ dr = dt->dt_rec;
+ MDNS_INIT_ASSERT(dr, dr_magic);
+ dbr = dr->dr_dbr;
+ MDNS_INIT_ASSERT(dbr, dbr_magic);
+
+ /*
+ * We should never get a "pointer resource" here, they are updated
+ * when the rrset they point to are updated.
+ */
+ assert(!(ds->ds_flags & DS_POINTER));
+
+ if (dr->dr_flags & DR_PROBING)
+ dbr_probe_del(dr);
+ if (dr->dr_flags & DR_ANNOUNCE)
+ dbr_an_del(dr);
+
+ vtd = var_expand(&dbr->dbr_vars, ds->ds_vdata.wp, &vtd_len);
+ names = malloc(sizeof(wchar_t *) * vtd_len);
+ for (i = 0; i < vtd_len; i++) {
+ names[i] = vtd[i].vtd_str;
+ }
+ res_update(ds, names, vtd_len);
+ free(vtd);
+
+ if (dr->dr_flags & DR_OK) {
+ pac = dbr_pac_new(dbr, PAC_ANNOUNCE);
+ dbr_an_add(pac, dr);
+ dbr_an_start(pac);
+ }
+ else {
+ pac = dbr_pac_new(dbr, PAC_PROBE);
+ dbr_probe_add(pac, dr);
+ dbr_probe_start(pac);
+ }
+}
+/*
+ * Add a resource to database record
+ * dr - Parent database record
+ * type - DNS type
+ * ttl - Resource TTL
+ * res - Unexpanded resource string
+ */
struct dbr_res *
-dbr_res_add(struct dbr_rec *dr, uint16_t type, uint32_t ttl, wchar_t *res)
+dbr_res_add(struct dbr_rec *dr, uint16_t type, uint32_t ttl, void *res, int ptr)
{
struct record *r;
+ struct record_type *rt, *rt2;
struct record_res *rr;
- struct record_type *rt, *rt2;
struct dbr *dbr;
- struct dbr_rec *dr_orig;
- struct dbr_res *ds, *ds2;
+ struct dbr_rec *dr_orig, *drp, *drp2;
+ struct dbr_res *ds;
struct dbr_type *dt;
struct vt_data *vtd;
- size_t vtd_len, i, j, rlen;
- char *p;
+ size_t vtd_len, j, namlen;
+ wchar_t *wp, **names;
+ char *ident;
MDNS_INIT_ASSERT(dr, dr_magic);
dbr = dr->dr_dbr;
MDNS_INIT_ASSERT(dbr, dbr_magic);
+ wp = res;
+ ident = res;
+ names = NULL;
+ namlen = 0;
+
+ /*
+ * If we where passed a pointer, make sure it exists.
+ */
+ if (ptr) {
+ drp = hashtbl_find(&dbr->dbr_ident, ident, strlen(ident));
+ if (drp == NULL)
+ return (NULL);
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list