PERFORCE change 127139 for review
Fredrik Lindberg
fli at FreeBSD.org
Wed Oct 3 13:55:58 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=127139
Change 127139 by fli at fli_nexus on 2007/10/03 20:55:24
- Add proper support for other classes than IN.
- Make the "API" more flexible and easier to use.
- Add better search and traverse functions.
Affected files ...
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/record.c#6 edit
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/record.h#4 edit
Differences ...
==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/record.c#6 (text+ko) ====
@@ -37,97 +37,166 @@
dprintf(DEBUG_REC, "Refcount on r=%x increased to %d",\
r, (r)->r_refcnt);
+#define record_class_aquire(rc) (rc)->rc_refcnt++; \
+ dprintf(DEBUG_REC, "Refcount on rc=%x increased to %d",\
+ rc, (rc)->rc_refcnt);
+
#define record_type_aquire(rt) (rt)->rt_refcnt++; \
dprintf(DEBUG_REC, "Refcount on rt=%x increased to %d",\
rt, (rt)->rt_refcnt);
+static inline int notify_parent(struct recpar *);
+
/*
* Initialize a record set for `class'
*/
-void
-records_init(struct records *recs, int class)
+int
+records_init(struct records *recs)
{
+ int error;
- recs->r_class = class;
- hashtbl_init(&recs->r_recs, 2, 131072, 5);
+ error = hashtbl_init(&recs->r_recs, 2, 131072, 5);
+ if (error != 0)
+ return (-1);
+ TAILQ_INIT(&recs->r_rec_list);
MDNS_INIT_SET(recs, r_magic);
+ return (0);
}
-static void
-rec_free(__unused struct hashtbl *ht, __unused const void *key,
- __unused size_t keylen, void *data, __unused void *arg)
+void
+records_destroy(struct records *recs)
{
- struct record *r = (struct record *)data;
+ struct record *r, *r2;
+ struct record_class *rc, *rc2;
struct record_type *rt, *rt2;
struct record_res *rr, *rr2;
+ int refcnt;
+
+ MDNS_INIT_ASSERT(recs, r_magic);
+
+ TAILQ_FOREACH_SAFE(r, &recs->r_rec_list, r_next, r2) {
+ r->r_flags |= REC_FORCE;
+ TAILQ_FOREACH_SAFE(rc, &r->r_list, rc_next, rc2) {
+ rc->rc_flags |= REC_FORCE;
+ TAILQ_FOREACH_SAFE(rt, &rc->rc_list, rt_next, rt2) {
+ rt->rt_flags |= REC_FORCE;
+ TAILQ_FOREACH_SAFE(rr, &rt->rt_list, rr_next,
+ rr2) {
+ rr->rr_flags |= REC_FORCE;
+ record_res_del(rr);
+ }
+ }
+ }
+ }
- MDNS_INIT_ASSERT(r, r_magic);
+ TAILQ_FOREACH_SAFE(r, &recs->r_rec_list, r_next, r2) {
+ TAILQ_FOREACH_SAFE(rc, &r->r_list, rc_next, rc2) {
+ TAILQ_FOREACH_SAFE(rt, &rc->rc_list, rt_next, rt2) {
+ refcnt = rt->rt_refcnt;
+ while (refcnt-- > 0)
+ record_type_release(rt);
+ }
+ }
+ }
- /*
- * Release record resources, note that we do not need an explicit call
- * to record_type_release, it will be called by record_res_del.
- */
- TAILQ_FOREACH_SAFE(rt, &r->r_list, rt_next, rt2) {
- TAILQ_FOREACH_SAFE(rr, &rt->rt_list, rr_next, rr2) {
- record_res_del(rr);
+ TAILQ_FOREACH_SAFE(r, &recs->r_rec_list, r_next, r2) {
+ TAILQ_FOREACH_SAFE(rc, &r->r_list, rc_next, rc2) {
+ refcnt = rc->rc_refcnt;
+ while (refcnt-- > 0) {
+ record_class_release(rc);
+ }
}
}
+
+ TAILQ_FOREACH_SAFE(r, &recs->r_rec_list, r_next, r2) {
+ refcnt = r->r_refcnt;
+ while (refcnt-- > 0)
+ record_release(r);
+ }
+
+ hashtbl_destroy(&recs->r_recs);
+ MDNS_INIT_UNSET(recs, r_magic);
}
-/*
- * Destroy a record set and free all resources
- */
-void
-records_destroy(struct records *recs)
+static inline int
+notify_parent(struct recpar *rp)
{
+ int error;
- hashtbl_walk(&recs->r_recs, rec_free, NULL);
- hashtbl_destroy(&recs->r_recs);
- MDNS_INIT_UNSET(recs, r_magic);
+ if (rp->rp_del_cb != NULL && rp->rp_handle != NULL) {
+ error = rp->rp_del_cb(rp->rp_handle);
+ if (error != 0) {
+ dprintf(DEBUG_REC, "Parent handle failed to remove "
+ "itself, handle=%p, cb=%p", rp->rp_handle,
+ rp->rp_del_cb);
+ return (-1);
+ }
+ }
+ return (0);
}
/*
* Get handle to record `name', initialize if this is the first reference
- * recs - Record set
- * r - Pointer to record
- * name - Resource name
- * flags - RECORD_NOALLOC will supress memory allocation
+ * recs - Record set
+ * r - Pointer to record
+ * parent - Pointer to parent record or NULL
+ * flags - RECORD_* flags
+ * name - Record resource name (utf-8)
*/
int
-record_get(struct records *recs, struct record **r, int flags, char *name)
+record_get(struct records *recs, struct record **r, struct recpar *parent,
+ int flags, const char *name)
{
- ssize_t len;
+ int error;
+ ssize_t len, namlen;
struct record *rec;
- char namlc[MDNS_RECORD_LEN+1];
+ char namlc[MDNS_RECORD_LEN];
MDNS_INIT_ASSERT(recs, r_magic);
len = utf8_tolower(name, namlc, MDNS_RECORD_LEN);
- if (len <= 0)
- return (-1);
+ if (len <= 0 || len >= MDNS_RECORD_LEN) {
+ goto record_get_fail;
+ }
rec = hashtbl_find(&recs->r_recs, namlc, len);
- if (rec == NULL && (flags & RECORD_NOINIT)) {
+ if (rec == NULL && (flags & REC_NOINIT)) {
*r = NULL;
return (0);
}
- if (len > MDNS_RECORD_LEN) {
- *r = NULL;
- return (-1);
- }
-
if (rec == NULL) {
- if (!(flags & RECORD_NOALLOC))
+ namlen = strlen(name);
+ if (namlen <= 0 || namlen >= MDNS_RECORD_LEN)
+ goto record_get_fail;
+ if (!(flags & REC_NOALLOC))
*r = malloc(sizeof(struct record));
+ if (*r == NULL)
+ goto record_get_fail;
+
MDNS_INIT_SET((*r), r_magic);
(*r)->r_recs = recs;
- (*r)->r_parent = NULL;
+
+ if (parent != NULL)
+ memcpy(&((*r)->r_parent), parent,
+ sizeof(struct recpar));
+ else {
+ (*r)->r_parent.rp_handle = NULL;
+ (*r)->r_parent.rp_del_cb = NULL;
+ }
+
(*r)->r_refcnt = 0;
(*r)->r_flags = flags;
TAILQ_INIT(&((*r)->r_list));
- memcpy((*r)->r_name, name, len+1);
- hashtbl_add(&recs->r_recs, namlc, len, *r, HASHTBL_KEYDUP);
+ memcpy((*r)->r_name, name, namlen+1);
+ error = hashtbl_add(&recs->r_recs, namlc, len, *r,
+ HASHTBL_KEYDUP);
+ if (error < 0) {
+ if (!(flags & REC_NOALLOC))
+ free(*r);
+ goto record_get_fail;
+ }
+ TAILQ_INSERT_TAIL(&recs->r_rec_list, (*r), r_next);
}
else {
*r = rec;
@@ -136,6 +205,9 @@
dprintf(DEBUG_REC, "Record aquired r=%x, name=%s, refcnt=%d",
*r, (*r)->r_name, (*r)->r_refcnt);
return (0);
+record_get_fail:
+ dprintf(DEBUG_REC, "Failed to aquire record name=%s", name);
+ return (-1);
}
/*
@@ -143,12 +215,13 @@
* was the last reference.
* r - Record to release
*/
-void
+int
record_release(struct record *r)
{
+ int error, flags;
ssize_t len;
struct records *recs;
- char namlc[MDNS_RECORD_LEN+1];
+ char namlc[MDNS_RECORD_LEN];
MDNS_INIT_ASSERT(r, r_magic);
recs = r->r_recs;
@@ -156,112 +229,291 @@
if (--r->r_refcnt == 0) {
assert(TAILQ_EMPTY(&r->r_list) == 1);
+ flags = r->r_flags;
+
len = utf8_tolower(r->r_name, namlc, MDNS_RECORD_LEN);
- hashtbl_del(&recs->r_recs, namlc, len);
+ if (len <= 0 || len >= MDNS_RECORD_LEN)
+ goto record_release_fail;
+
+ error = hashtbl_del(&recs->r_recs, namlc, len);
+ if (error < 0)
+ goto record_release_fail;
+ TAILQ_REMOVE(&recs->r_rec_list, r, r_next);
MDNS_INIT_UNSET(r, r_magic);
- if (!(r->r_flags & RECORD_NOALLOC))
+
+ error = notify_parent(&r->r_parent);
+ if (error != 0 && !(flags & REC_FORCE)) {
+ MDNS_INIT_SET(r, r_magic);
+ TAILQ_INSERT_TAIL(&recs->r_rec_list, r, r_next);
+ hashtbl_add(&recs->r_recs, namlc, len, r,
+ HASHTBL_KEYDUP);
+ goto record_release_fail;
+ }
+
+ if (!(flags & REC_NOALLOC))
free(r);
- dprintf(DEBUG_REC, "References cleared on r=%x, removed", r);
+ dprintf(DEBUG_REC, "References cleared on r=%p, removed", r);
}
else {
- dprintf(DEBUG_REC, "Record released r=%x, refs=%d",
+ dprintf(DEBUG_REC, "Record released r=%p, refs=%d",
r, r->r_refcnt);
}
+ return (0);
+record_release_fail:
+ r->r_refcnt++;
+ dprintf(DEBUG_REC, "Failed to release record %p", r);
+ return (-1);
}
/*
* Modify the name of a record in-place without releasing
* types and resources.
*/
-void
-record_setname(struct record *r, char *name)
+int
+record_setname(struct record *r, const char *name)
{
struct records *recs;
- size_t len;
+ size_t len, namlen, rlen;
+ int error;
+ char namlc[MDNS_RECORD_LEN], namlc2[MDNS_RECORD_LEN];
MDNS_INIT_ASSERT(r, r_magic);
recs = r->r_recs;
MDNS_INIT_ASSERT(recs, r_magic);
- len = strlen(r->r_name);
- hashtbl_del(&recs->r_recs, r->r_name, len);
- len = strlen(name);
- memcpy(r->r_name, name, len+1);
- hashtbl_add(&recs->r_recs, r->r_name, len, r, 0);
- dprintf(DEBUG_REC, "Record name set to %s on r=%x", r->r_name, r);
+ namlen = strlen(name);
+ if (namlen <= 0 || namlen >= MDNS_RECORD_LEN)
+ goto record_setname_fail;
+
+ len = utf8_tolower(name, namlc, MDNS_RECORD_LEN);
+ if (len <= 0 || len >= MDNS_RECORD_LEN)
+ goto record_setname_fail;
+
+ rlen = utf8_tolower(r->r_name, namlc2, MDNS_RECORD_LEN);
+ if (rlen <= 0 || rlen >= MDNS_RECORD_LEN)
+ goto record_setname_fail;
+
+ error = hashtbl_add(&recs->r_recs, namlc, len, r, HASHTBL_KEYDUP);
+ if (error < 0)
+ goto record_setname_fail;
+
+ error = hashtbl_del(&recs->r_recs, namlc2, rlen);
+ if (error < 0) {
+ hashtbl_del(&recs->r_recs, namlc, len);
+ goto record_setname_fail;
+ }
+
+ memcpy(r->r_name, name, namlen + 1);
+
+ dprintf(DEBUG_REC, "Record name set to %s on r=%p", r->r_name, r);
+ return (0);
+record_setname_fail:
+ dprintf(DEBUG_REC, "Failed to set name on r=%p to %s", r, name);
+ return (-1);
+}
+
+int
+record_class_get(struct records *recs, struct record_class **rc, int flags,
+ struct recpar *rp, void *record, uint16_t class)
+{
+ int error, nflags;
+ struct record *r;
+ struct record_class *rc2;
+
+ MDNS_INIT_ASSERT(recs, r_magic);
+
+ if (flags & REC_OBJNAME) {
+ r = record;
+ MDNS_INIT_ASSERT(r, r_magic);
+ record_aquire(r);
+ }
+ else {
+ nflags = flags & ~(REC_NOALLOC | REC_NOINIT);
+ error = record_get(recs, &r, NULL, nflags, record);
+ if (error < 0)
+ goto record_class_get_fail;
+ }
+
+ TAILQ_FOREACH(rc2, &r->r_list, rc_next)
+ if (class == rc2->rc_class)
+ break;
+ if (rc2 == NULL && (flags & REC_NOINIT)) {
+ record_release(r);
+ *rc = NULL;
+ return (0);
+ }
+
+ if (rc2 == NULL) {
+ if (!(flags & REC_NOALLOC))
+ *rc = malloc(sizeof(struct record_class));
+ if (*rc == NULL)
+ goto record_class_get_fail;
+ MDNS_INIT_SET((*rc), rc_magic);
+ (*rc)->rc_class = class;
+ (*rc)->rc_record = r;
+ (*rc)->rc_refcnt = 0;
+ (*rc)->rc_flags = flags;
+
+ if (rp != NULL)
+ memcpy(&(*rc)->rc_parent, rp, sizeof(struct recpar));
+ else {
+ (*rc)->rc_parent.rp_handle = NULL;
+ (*rc)->rc_parent.rp_del_cb = NULL;
+ }
+
+ TAILQ_INIT(&((*rc)->rc_list));
+ TAILQ_FOREACH(rc2, &r->r_list, rc_next)
+ if (rc2->rc_class > class)
+ break;
+ if (rc2 != NULL)
+ TAILQ_INSERT_BEFORE(rc2, *rc, rc_next);
+ else
+ TAILQ_INSERT_TAIL(&r->r_list, *rc, rc_next);
+ }
+ else {
+ *rc = rc2;
+ }
+
+ record_class_aquire(*rc);
+ dprintf(DEBUG_REC, "Record class aquired rc=%x, refcnt=%d", *rc,
+ (*rc)->rc_refcnt);
+ return (0);
+record_class_get_fail:
+ dprintf(DEBUG_REC, "Failed to aquire class %d", class);
+ return (-1);
}
/*
- * Lookup if a record exists
+ * Release a record class
*/
-struct record *
-record_find(struct records *recs, char *name)
+int
+record_class_release(struct record_class *rc)
{
struct record *r;
- ssize_t len;
- char namlc[MDNS_RECORD_LEN+1];
+ struct record_class *rc2;
+ int error, flags;
+
+ MDNS_INIT_ASSERT(rc, rc_magic);
+ r = rc->rc_record;
+ MDNS_INIT_ASSERT(r, r_magic);
+
+ if (--rc->rc_refcnt == 0) {
+ assert(TAILQ_EMPTY(&rc->rc_list) == 1);
+ flags = rc->rc_flags;
- MDNS_INIT_ASSERT(recs, r_magic);
+ TAILQ_REMOVE(&r->r_list, rc, rc_next);
+ MDNS_INIT_UNSET(rc, rc_magic);
- len = utf8_tolower(name, namlc, MDNS_RECORD_LEN);
- if (len <= 0)
- return (NULL);
+ error = notify_parent(&rc->rc_parent);
+ if (error != 0 && !(flags & REC_FORCE)) {
+ MDNS_INIT_SET(rc, rc_magic);
+ TAILQ_FOREACH(rc2, &r->r_list, rc_next)
+ if (rc->rc_class > rc2->rc_class)
+ break;
+ if (rc2 != NULL)
+ TAILQ_INSERT_BEFORE(rc2, rc, rc_next);
+ else
+ TAILQ_INSERT_TAIL(&r->r_list, rc, rc_next);
+ goto record_class_release_fail;
+ }
- r = hashtbl_find(&recs->r_recs, namlc, len);
- return (r);
+ if (!(flags & REC_NOALLOC))
+ free(rc);
+ dprintf(DEBUG_REC, "References cleared on rc=%x, removed", rc);
+ }
+ else {
+ dprintf(DEBUG_REC, "Record class released rc=%x, refcnt=%d",
+ rc, rc->rc_refcnt);
+ }
+ record_release(r);
+ return (0);
+record_class_release_fail:
+ rc->rc_refcnt++;
+ dprintf(DEBUG_REC, "Failed to release record class rc=%p", rc);
+ return (-1);
}
+
/*
- * Get a record type for a record, will be intialized if needed
- * r - Record
- * rt - Pointer to the new record type
- * flags - RECORD_NOALLOC will supress memory allocation
- * type - DNS type
+ * Aquire reference to a record type
*/
int
-record_type_get(struct record *r, struct record_type **rt, int flags,
- uint16_t type)
+record_type_get(struct records *recs, struct record_type **rt, int flags,
+ struct recpar *rp, void *record, uintptr_t class, uint16_t type)
{
+ int error, nflags;
struct record_type *rt2;
+ struct record_class *rc = NULL;
+
+ MDNS_INIT_ASSERT(recs, r_magic);
- MDNS_INIT_ASSERT(r, r_magic);
+ if (flags & REC_OBJCLASS) {
+ rc = (struct record_class *)class;
+ MDNS_INIT_ASSERT(rc, rc_magic);
+ record_aquire(rc->rc_record);
+ record_class_aquire(rc);
+ }
+ else {
+ nflags = flags & ~(REC_NOALLOC | REC_NOINIT);
+ error = record_class_get(recs, &rc, nflags, NULL,
+ record, class);
+ if (error < 0)
+ goto record_type_get_fail2;
+ }
+
+ assert(rc != NULL);
- TAILQ_FOREACH(rt2, &r->r_list, rt_next) {
+ TAILQ_FOREACH(rt2, &rc->rc_list, rt_next) {
if (type == rt2->rt_type)
break;
}
- if (rt2 == NULL && (flags & RECORD_NOINIT)) {
+
+ if ((rt2 == NULL) && (flags & REC_NOINIT)) {
*rt = NULL;
+ record_class_release(rc);
return (0);
}
+ else if (rt2 != NULL) {
+ *rt = rt2;
+ goto record_type_get_out;
+ }
+
+ assert(rt2 == NULL);
+ if (!(flags & REC_NOALLOC))
+ *rt = malloc(sizeof(struct record_type));
+ if (*rt == NULL)
+ goto record_type_get_fail;
- if (rt2 == NULL) {
- if (!(flags & RECORD_NOALLOC))
- *rt = malloc(sizeof(struct record_type));
- MDNS_INIT_SET((*rt), rt_magic);
- (*rt)->rt_parent = NULL;
- (*rt)->rt_type = type;
- (*rt)->rt_flags = flags;
- (*rt)->rt_record = r;
- (*rt)->rt_refcnt = 0;
- record_aquire(r);
- TAILQ_INIT(&((*rt)->rt_list));
- TAILQ_FOREACH(rt2, &r->r_list, rt_next) {
- if (type > rt2->rt_type)
- break;
- }
- if (rt2 != NULL)
- TAILQ_INSERT_BEFORE(rt2, *rt, rt_next);
- else
- TAILQ_INSERT_TAIL(&r->r_list, *rt, rt_next);
- }
+ MDNS_INIT_SET((*rt), rt_magic);
+ if (rp != NULL)
+ memcpy(&((*rt)->rt_parent), rp, sizeof(struct recpar));
else {
- *rt = rt2;
+ (*rt)->rt_parent.rp_handle = NULL;
+ (*rt)->rt_parent.rp_del_cb = NULL;
}
+ (*rt)->rt_type = type;
+ (*rt)->rt_flags = flags;
+ (*rt)->rt_class = rc;
+ (*rt)->rt_refcnt = 0;
+ TAILQ_INIT(&((*rt)->rt_list));
+ TAILQ_FOREACH(rt2, &rc->rc_list, rt_next)
+ if (rt2->rt_type > type)
+ break;
+ if (rt2 != NULL)
+ TAILQ_INSERT_BEFORE(rt2, *rt, rt_next);
+ else
+ TAILQ_INSERT_TAIL(&rc->rc_list, *rt, rt_next);
+
+record_type_get_out:
record_type_aquire(*rt);
dprintf(DEBUG_REC, "Record type aquired rt=%x, refcnt=%d", *rt,
(*rt)->rt_refcnt);
return (0);
+record_type_get_fail:
+ record_class_release(rc);
+record_type_get_fail2:
+ dprintf(DEBUG_REC, "Failed to aquire record type %d", type);
+ return (-1);
}
/*
@@ -269,79 +521,154 @@
* was the last reference.
* rt - Record type to release
*/
-void
+int
record_type_release(struct record_type *rt)
{
- struct record *r;
+ struct record_class *rc;
+ struct record_type *rt2;
+ int error, flags;
MDNS_INIT_ASSERT(rt, rt_magic);
+ rc = rt->rt_class;
+ MDNS_INIT_ASSERT(rc, rc_magic);
+
if (--rt->rt_refcnt == 0) {
- r = rt->rt_record;
- TAILQ_REMOVE(&r->r_list, rt, rt_next);
+ assert(TAILQ_EMPTY(&rt->rt_list) == 1);
+ flags = rt->rt_flags;
+
+ TAILQ_REMOVE(&rc->rc_list, rt, rt_next);
MDNS_INIT_UNSET(rt, rt_magic);
- if (!(rt->rt_flags & RECORD_NOALLOC))
+
+ error = notify_parent(&rt->rt_parent);
+ if (error != 0 && !(flags & REC_FORCE)) {
+ MDNS_INIT_SET(rt, rt_magic);
+ TAILQ_FOREACH(rt2, &rc->rc_list, rt_next)
+ if (rt->rt_type > rt2->rt_type)
+ break;
+ if (rt2 != NULL)
+ TAILQ_INSERT_BEFORE(rt2, rt, rt_next);
+ else
+ TAILQ_INSERT_TAIL(&rc->rc_list, rt, rt_next);
+ goto record_type_release_fail;
+ }
+ if (!(flags & REC_NOALLOC))
free(rt);
+
dprintf(DEBUG_REC, "References cleared on rt=%x, removed", rt);
- record_release(r);
}
else {
dprintf(DEBUG_REC, "Record type released rt=%x, refcnt=%d",
rt, rt->rt_refcnt);
}
+ record_class_release(rc);
+ return (0);
+record_type_release_fail:
+ rt->rt_refcnt++;
+ dprintf(DEBUG_REC, "Failed to release record type rt=%p", rt);
+ return (-1);
}
/*
* Add a resource record to a resource type
- * r - Parent record
- * rr - Initialized to the new resource record
- * flags - RECORD_ALLOC will cause it to allocated memory if needed
- * type - DNS type
- * data - Pointer to resource data
- * dlen - Length of resource data
*/
int
-record_res_add(struct record *r, struct record_res **rr, int flags,
- uint16_t type, void *data, size_t dlen)
+record_res_add(struct records *recs, struct record_res **rr, int flags,
+ struct recpar *rp, void *record, uintptr_t class, uintptr_t type,
+ void *data, size_t dlen)
{
struct record_type *rt;
+ int error, nflags;
+
+ MDNS_INIT_ASSERT(recs, r_magic);
- MDNS_INIT_ASSERT(r, r_magic);
+ if (flags & REC_OBJTYPE) {
+ rt = (struct record_type *)type;
+ MDNS_INIT_ASSERT(rt, rt_magic);
+ record_aquire(rt->rt_class->rc_record);
+ record_class_aquire(rt->rt_class);
+ record_type_aquire(rt);
+ }
+ else {
+ nflags = flags & ~(REC_NOALLOC | REC_NOINIT);
+ error = record_type_get(recs, &rt, nflags, NULL, record,
+ class, type);
+ if (error != 0)
+ goto record_res_add_fail;
+ }
+
+ assert(rt != NULL);
- record_type_get(r, &rt, 0, type);
- if (!(flags & RECORD_NOALLOC))
+ if (!(flags & REC_NOALLOC))
*rr = malloc(sizeof(struct record_res));
+ if (*rr == NULL)
+ goto record_res_add_fail;
MDNS_INIT_SET((*rr), rr_magic);
- (*rr)->rr_parent = NULL;
(*rr)->rr_flags = flags;
- (*rr)->rr_data = data; /* FIXME: assumption, new flag */
+
+ if (rp != NULL)
+ memcpy(&((*rr)->rr_parent), rp, sizeof(struct recpar));
+ else {
+ (*rr)->rr_parent.rp_handle = NULL;
+ (*rr)->rr_parent.rp_del_cb = NULL;
+ }
+
+ if (flags & REC_RESDUP) {
+ (*rr)->rr_data = malloc(dlen);
+ if ((*rr)->rr_data == NULL)
+ goto record_res_add_fail;
+ memcpy((*rr)->rr_data, data, dlen);
+ }
+ else
+ (*rr)->rr_data = data;
(*rr)->rr_len = dlen;
(*rr)->rr_type = rt;
TAILQ_INSERT_TAIL(&rt->rt_list, *rr, rr_next);
- dprintf(DEBUG_REC, "Resource rr=%x added on r=%x, rt=%x", *rr, r, rt);
+
+ dprintf(DEBUG_REC, "Resource rr=%p added rt=%p", *rr, rt);
return (0);
+record_res_add_fail:
+ if ((!(flags & REC_NOALLOC)) && *rr != NULL)
+ free(*rr);
+ record_type_release(rt);
+ dprintf(DEBUG_REC, "Failed to add resource data=%p, rt=%p", data, rt);
+ return (-1);
}
/*
* Delete a resource record
* rr - Pointer to resource record
*/
-void
+int
record_res_del(struct record_res *rr)
{
- int flags;
+ int flags, error;
struct record_type *rt;
+ void *dptr;
MDNS_INIT_ASSERT(rr, rr_magic);
rt = rr->rr_type;
MDNS_INIT_ASSERT(rt, rt_magic);
flags = rr->rr_flags;
+ dptr = rr->rr_data;
+
TAILQ_REMOVE(&rt->rt_list, rr, rr_next);
- free(rr->rr_data); /* FIXME assumption */
- record_type_release(rt);
MDNS_INIT_UNSET(rr, rr_magic);
- if (!(flags & RECORD_NOALLOC))
+ error = notify_parent(&rr->rr_parent);
+ if (error != 0 && !(flags & REC_FORCE)) {
+ MDNS_INIT_SET(rr, rr_magic);
+ TAILQ_INSERT_TAIL(&rt->rt_list, rr, rr_next);
+ goto record_res_del_fail;
+ }
+ if (!(flags & REC_NOALLOC))
free(rr);
+ if (flags & (REC_RESOWN | REC_RESDUP))
+ free(dptr);
+ record_type_release(rt);
dprintf(DEBUG_REC, "Resource rr=%x removed, rt=%x", rr, rt);
+ return (0);
+record_res_del_fail:
+ dprintf(DEBUG_REC, "Failed to remove resource rr=%p", rr);
+ return (-1);
}
/*
@@ -350,34 +677,54 @@
* data - Data pointer
* dlen - Length of data
*/
-void
-record_res_setdata(struct record_res *rr, void *data, size_t dlen)
+int
+record_res_setdata(struct record_res *rr, int flags, void *data, size_t dlen)
{
+ void *dptr, *dup;
MDNS_INIT_ASSERT(rr, rr_magic);
- free(rr->rr_data); /* FIXME: assumption */
- rr->rr_data = data;
+ dptr = rr->rr_data;
+
+ if (flags & REC_RESDUP) {
+ dup = malloc(dlen);
+ if (dup == NULL)
+ goto record_res_setdata_fail;
+ memcpy(dup, data, dlen);
+ rr->rr_data = dup;
+ rr->rr_flags |= REC_RESDUP;
+ }
+ else {
+ rr->rr_data = data;
+ rr->rr_flags &= ~REC_RESDUP;
+ }
+
+ if (rr->rr_flags & (REC_RESOWN | REC_RESDUP))
+ free(dptr);
+
+ if (flags & REC_RESOWN)
+ rr->rr_flags |= REC_RESOWN;
+ else
+ rr->rr_flags &= ~(REC_RESOWN);
+
rr->rr_len = dlen;
dprintf(DEBUG_REC, "Resource data set on rr=%x, data=%x, dlen=%d",
rr, data, dlen);
+ return (0);
+record_res_setdata_fail:
+ dprintf(DEBUG_REC, "Failed to set resource data on rr=%p, data=%p, "
+ "dlen=%d", rr, data, dlen);
+ return (-1);
}
-
/*
- * Returns a pointer to the first resource record identified by (name, type)
- * recs - Record set
- * name - Resource name
- * type - Resource type
+ * Lookup if a record exists
*/
-struct record_res *
-record_res_find(struct records *recs, char *name, uint16_t type, char *data,
- size_t dlen)
+struct record *
+record_find(struct records *recs, const char *name)
{
struct record *r;
- struct record_type *rt;
- struct record_res *rr;
ssize_t len;
- char namlc[MDNS_RECORD_LEN+1];
+ char namlc[MDNS_RECORD_LEN];
MDNS_INIT_ASSERT(recs, r_magic);
@@ -386,110 +733,154 @@
return (NULL);
r = hashtbl_find(&recs->r_recs, namlc, len);
- if (r == NULL)
- return (NULL);
+ return (r);
+}
+
+struct record_class *
+record_class_find(struct records *recs, int flags, const void *record,
+ uint16_t class)
+{
+ const struct record *r;
+ struct record_class *rc;
+
+ MDNS_INIT_ASSERT(recs, r_magic);
+ if (flags & REC_OBJNAME) {
+ r = (const struct record *)record;
+ MDNS_INIT_ASSERT(r, r_magic);
+ }
+ else {
+ r = record_find(recs, record);
+ if (r == NULL)
+ return (NULL);
+ }
+
+ if ((flags & REC_CTANY) && rc->rc_class == mdns_c_any) {
+ rc = record_class_first(r);
+ if (rc != NULL)
+ rc->rc_flags |= REC_CTANY;
+ return (rc);
+ }
- TAILQ_FOREACH(rt, &r->r_list, rt_next) {
- if (rt->rt_type == type)
- break;
+ rc = NULL;
+ TAILQ_FOREACH(rc, &r->r_list, rc_next) {
+ if (rc->rc_class < class)
+ continue;
+ if (rc->rc_class > class)
+ rc = NULL;
+ break;
}
- if (rt == NULL)
+ return (rc);
+}
+
+/*
+ * Obtain next logical record class, only applicable when the record class
+ * is mdns_c_any and the flag REC_CTANY is set.
+ */
+struct record_class *
+record_class_find_next(struct record_class *rc, uint16_t class)
+{
+ struct record_class *rc2;
+
+ if (!(rc->rc_flags & REC_CTANY))
+ return (NULL);
+ else if (class != mdns_c_any)
return (NULL);
- TAILQ_FOREACH(rr, &rt->rt_list, rr_next) {
- if (rr->rr_len == dlen)
- if (memcmp(rr->rr_data, data, dlen) == 0)
- break;
- }
- return (rr);
+ rc->rc_flags &= ~REC_CTANY;
+ rc2 = record_class_next(rc);
+ if (rc2 != NULL)
+ rc2->rc_flags |= REC_CTANY;
+ return (rc2);
}
struct record_type *
-record_type_find(struct records *recs, char *name, uint16_t type)
+record_type_find(struct records *recs, int flags, const void *record,
+ uintptr_t class, uint16_t type)
{
- struct record *r;
+ struct record_class *rc;
struct record_type *rt;
- ssize_t len;
- char namlc[MDNS_RECORD_LEN+1];
MDNS_INIT_ASSERT(recs, r_magic);
- len = utf8_tolower(name, namlc, MDNS_RECORD_LEN);
- if (len <= 0)
- return (NULL);
+ if (flags & REC_OBJCLASS) {
+ rc = (struct record_class *)class;
+ MDNS_INIT_ASSERT(rc, rc_magic);
+ }
+ else {
+ rc = record_class_find(recs, flags, record, class);
+ if (rc == NULL)
+ return (NULL);
+ }
- r = hashtbl_find(&recs->r_recs, namlc, len);
- if (r == NULL)
- return (NULL);
+ if ((flags & REC_CTANY) && rt->rt_type == mdns_t_any) {
+ rt = record_type_first(rc);
+ if (rt != NULL)
+ rt->rt_flags |= REC_CTANY;
+ return (rt);
+ }
- TAILQ_FOREACH(rt, &r->r_list, rt_next) {
- if (rt->rt_type == type)
- break;
+ rt = NULL;
+ TAILQ_FOREACH(rt, &rc->rc_list, rt_next) {
+ if (rt->rt_type < type)
+ continue;
+ if (rt->rt_type > type)
+ rt = NULL;
+ break;
}
return (rt);
}
-static void
-rec_walk(__unused struct hashtbl *ht, __unused const void *key,
- __unused size_t keylen, void *data, void *arg)
+struct record_type *
+record_type_find_next(struct record_type *rt, uint16_t type)
{
- void **args = (void **)arg;
- record_foreach cb = args[0];
- void *cbarg = args[1];
- struct record *r = data;
+ struct record_type *rt2;
+
+ if (!(rt->rt_flags & REC_CTANY))
+ return (NULL);
+ else if (type != mdns_t_any)
+ return (NULL);
- cb(r, cbarg);
+ rt->rt_flags &= ~REC_CTANY;
+ rt2 = record_type_next(rt);
+ if (rt2 != NULL)
+ rt2->rt_flags |= REC_CTANY;
+ return (rt2);
}
-void
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list