Date: Wed, 3 Oct 2007 20:55:57 GMT From: Fredrik Lindberg <fli@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 127139 for review Message-ID: <200710032055.l93Ktvvs093840@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=127139 Change 127139 by fli@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) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200710032055.l93Ktvvs093840>
