From owner-p4-projects@FreeBSD.ORG Mon Jul 16 00:55:34 2007 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id F146716A404; Mon, 16 Jul 2007 00:55:33 +0000 (UTC) X-Original-To: perforce@FreeBSD.org Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id B655416A402 for ; Mon, 16 Jul 2007 00:55:33 +0000 (UTC) (envelope-from fli@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.freebsd.org (Postfix) with ESMTP id A627313C441 for ; Mon, 16 Jul 2007 00:55:33 +0000 (UTC) (envelope-from fli@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id l6G0tX6p087198 for ; Mon, 16 Jul 2007 00:55:33 GMT (envelope-from fli@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id l6G0tXwn087195 for perforce@freebsd.org; Mon, 16 Jul 2007 00:55:33 GMT (envelope-from fli@FreeBSD.org) Date: Mon, 16 Jul 2007 00:55:33 GMT Message-Id: <200707160055.l6G0tXwn087195@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to fli@FreeBSD.org using -f From: Fredrik Lindberg To: Perforce Change Reviews Cc: Subject: PERFORCE change 123565 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 16 Jul 2007 00:55:34 -0000 http://perforce.freebsd.org/chv.cgi?CH=123565 Change 123565 by fli@fli_nexus on 2007/07/16 00:54:49 - Revisit packet construction. Instead of writing raw packets directly into a buffer, rrset/qset objects are kept on a list and the packet is written first when mdns_pkgchain_finalize(). is called. This simplifies packet constructions, allows resources to be both added and removed from a packet during construction. It also have the neat side effect that the heavy finalizing step can be moved to the output queue thread. - Use object allocator for packets. - Style fixes Affected files ... .. //depot/projects/soc2007/fli-mdns_sd/mdnsd/mdns.h#6 edit .. //depot/projects/soc2007/fli-mdns_sd/mdnsd/stack_packet.c#7 edit Differences ... ==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/mdns.h#6 (text+ko) ==== @@ -35,6 +35,7 @@ #include #include "stack_buf.h" +#include "threads.h" /* * Multicast DNS handle, holds socket and buffer information @@ -43,6 +44,7 @@ struct mdns { MAGIC(md_magic); char md_ifnam[IFNAMSIZ + 1]; + DEF_RW(md_lock); int md_ifindex; int md_flags; #define MDNS_UDP4 0x0001 /* udp inet4 socket open */ @@ -74,16 +76,17 @@ */ enum { MDNS_UDP, MDNS_TCP }; + /* * Packet buffer */ -struct mdns_namcomp; struct mdns_pkgchain; +struct mdns_pkg_res; struct mdns_packet { - uint32_t p_magic; + MAGIC(p_magic); struct mdns_pkgchain *p_pc; TAILQ_ENTRY(mdns_packet) p_list; /* packet list */ - size_t p_len; /* total packet length */ + size_t p_len; /* total packet length (without compression) */ struct mdns_bufhead p_buflist; /* @@ -96,37 +99,37 @@ char *bufptr; /* Direct buffer data pointer */ char **offsets; /* Section offset pointers */ int last_offset; + TAILQ_HEAD(, mdns_pkg_res) res_head; } p_data[4]; #define p_buf(x) p_data[x].bufptr #define p_bufseg(x) p_data[x].buf #define p_secoff(x) p_data[x].offsets #define p_loff(x) p_data[x].last_offset; +#define p_res(x) p_data[x].res_head; #define p_hdr 0 #define p_questions 1 #define p_answers 2 #define p_auths 3 #define p_isrrset(x) ((x) > 1) /* 0 = qset, 1 = rrset */ +}; - struct hashtbl *p_nc_tbl; /* Name compression hash */ -}; +/* + * Packet construction flags + */ +#define MDNS_PKG_NOAE 0x01 /* Do not auto-expand pkg chain */ +#define MDNS_PKG_DUP 0x02 /* Duplicate rrset/qset */ /* * Packet chain */ -typedef int (*md_lock)(void *); -typedef int (*md_unlock)(void *); struct mdns_pkgchain { MAGIC(pc_magic); TAILQ_HEAD(, mdns_packet) pc_head; /* packet list */ - int pc_list_len; /* packet list length */ int pc_flags; #define MDNS_PC_NONE 0x0 #define MDNS_PC_CONT 0x1 struct mdns *pc_md; /* back pointer */ struct mdns_packet *pc_pkg; /* current pkg buffer */ - md_lock pc_lock; /* lock function */ - md_unlock pc_unlock; /* lock function */ - void *pc_lockarg; /* lock argument */ }; @@ -183,7 +186,8 @@ * MDNS resource set */ struct mdns_rrset { - char r_name[MDNS_RECORD_LEN + 1]; /* rrset name */ + char name[MDNS_RECORD_LEN + 1]; /* rrset name */ + char *r_name; uint16_t r_class; /* rrset class */ uint16_t r_type; /* Record type */ int r_cflush; /* cache flush */ @@ -192,16 +196,42 @@ char *r_data; /* Resource data */ }; +#define mdns_rrset_name(rr, str) (rr)->r_name = str +#define mdns_rrset_name_dup(rr, str) \ + strncpy((rr)->name, str, MDNS_RECORD_LEN); \ + (rr)->r_name = (rr)->name; + /* * MDNS question/query set */ struct mdns_qset { - char q_name[MDNS_RECORD_LEN + 1]; /* qname */ + char name[MDNS_RECORD_LEN + 1]; /* qname */ + char *q_name; uint16_t q_class; /* qset class */ uint16_t q_type; /* query type */ int q_unicast; /* unicast desired */ }; +#define mdns_qset_name(qs, str) (qs)->q_name = str +#define mdns_qset_name_dup(qs, str) \ + strncpy((qs)->name, str, MDNS_RECORD_LEN); \ + (qs)->q_name = (qs)->name; + +/* + * Packet resource + * Used during packet construction + */ +struct mdns_pkg_res { + MAGIC(pr_magic); + TAILQ_ENTRY(mdns_pkg_res) pr_next; + int pr_what; /* rrset/qset */ + size_t pr_namlen; /* record name length */ + union { + struct mdns_rrset rs; + struct mdns_qset qs; + } pr_res; +}; + /* * Name/Resource encoding flags */ @@ -234,16 +264,27 @@ void *); int mdns_bufpool_destroy(struct mdns_bufpool *); -void mdns_pkgchain_init(struct mdns *, struct mdns_pkgchain *, - int, md_lock, md_unlock, void *); -void mdns_pkgchain_free(struct mdns *, struct mdns_pkgchain *); +void mdns_pkgchain_init(struct mdns *, struct mdns_pkgchain *, int); +void mdns_pkgchain_free(struct mdns_pkgchain *); struct mdns_packet * mdns_pkgchain_curpkg(struct mdns_pkgchain *); +void mdns_pkgchain_expand(struct mdns_pkgchain *); + +struct mdns_rrset * mdns_pkg_getrrset(void); +struct mdns_qset * mdns_pkg_getqset(void); +void mdns_pkg_freeset(void *); int mdns_pkg_sethdr(struct mdns_pkgchain *, uint16_t, int); int mdns_pkg_gethdr(struct mdns_packet *, struct mdns_head *); int mdns_pkg_addquestion(struct mdns_pkgchain *, struct mdns_qset *, int); +struct mdns_qset * mdns_pkg_delquestion(struct mdns_pkgchain *, + struct mdns_qset *); int mdns_pkg_addanswer(struct mdns_pkgchain *, struct mdns_rrset *, int); +struct mdns_rrset * mdns_pkg_delanswer(struct mdns_pkgchain *, + struct mdns_rrset *); int mdns_pkg_addauth(struct mdns_pkgchain *, struct mdns_rrset *, int); +struct mdns_rrset * mdns_pkg_delauth(struct mdns_pkgchain *, + struct mdns_rrset *); +int mdns_pkgchain_finalize(struct mdns_pkgchain *); int mdns_pkg_getquestion(struct mdns_packet *, int, struct mdns_qset *); int mdns_pkg_getanswer(struct mdns_packet *, int, struct mdns_rrset *); int mdns_pkg_getauth(struct mdns_packet *, int, struct mdns_rrset *); ==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/stack_packet.c#7 (text+ko) ==== @@ -36,9 +36,12 @@ #include #include +#include "debug.h" +#include "hash.h" +#include "log.h" #include "mdns.h" +#include "objalloc.h" #include "stack_mdns.h" -#include "hash.h" static inline char * skipname(char *, char *); static int name_compress(struct hashtbl *, char *, size_t, char *, @@ -48,9 +51,13 @@ static inline void res_encode(struct hashtbl *, char *, uint16_t, char *, size_t *, int); -static inline void free_pkg(struct mdns_packet *, struct mdns_bufpool *); +static void pkg_free(struct mdns_pkgchain *, struct mdns_packet *); +static int pkg_write(struct mdns_packet *, struct mdns_bufpool *); -static int addres(struct mdns_pkgchain *pc, int, struct mdns_rrset *, int); +static int addres(struct mdns_pkgchain *, int, void *, int, + struct mdns_packet **); +static struct mdns_pkg_res * delres(struct mdns_pkgchain *, int, void *, + struct mdns_packet **); static int getres(struct mdns_packet *, int, int, void *); enum { @@ -66,46 +73,68 @@ struct mdns_packet * pkg_alloc(struct mdns_pkgchain *pc) { - struct mdns *md; struct mdns_packet *pkg; - struct mdns_bufpool *bp; + int i; - md = pc->pc_md; - if (pc->pc_lock != NULL) - pc->pc_lock(pc->pc_lockarg); - - bp = md->md_bp; - - if (!TAILQ_EMPTY(&md->md_pkglist)) { - pkg = TAILQ_FIRST(&md->md_pkglist); - TAILQ_REMOVE(&md->md_pkglist, pkg, p_list); - md->md_pkgfree--; - } - else { - pkg = malloc(sizeof(struct mdns_packet)); - if (pkg == NULL) - goto error; - md->md_pkgtotal++; - } - + MDNS_INIT_ASSERT(pc, pc_magic); + pkg = obj_alloc(OBJ_PKG); bzero(pkg, sizeof(struct mdns_packet)); pkg->p_pc = pc; pc->pc_pkg = pkg; + for (i = 0; i < 4; i++) + TAILQ_INIT(&pkg->p_data[i].res_head); + MDNS_INIT_SET(pkg, p_magic); TAILQ_INSERT_TAIL(&pc->pc_head, pkg, p_list); - pc->pc_list_len++; - if (pc->pc_unlock != NULL) - pc->pc_unlock(pc->pc_lockarg); - + dprintf(DEBUG_STACK, "Allocated packet pkg=%x (pc=%x)", pkg, pc); return (pkg); -error: - if (pc->pc_unlock != NULL) - pc->pc_unlock(pc->pc_lockarg); - return (NULL); } /* + * Deallocates a packet from a packet chain and releases any + * allocted resources. + * pc - Packet chain + * pkg - Packet to remove (it's assumed that pkg belongs to pc) + */ +static void +pkg_free(struct mdns_pkgchain *pc, struct mdns_packet *pkg) +{ + struct mdns_pkg_res *pr, *pr2; + struct mdns_bufpool *bp; + struct mdns_buf *buf; + struct mdns *md; + int i; + + MDNS_INIT_ASSERT(pkg, p_magic); + MDNS_INIT_ASSERT(pc, pc_magic); + md = pc->pc_md; + MDNS_INIT_ASSERT(md, md_magic); + bp = md->md_bp; + + TAILQ_REMOVE(&pc->pc_head, pkg, p_list); + + /* Return buffers allocated to this packet */ + while (!TAILQ_EMPTY(&pkg->p_buflist.bh_list)) { + buf = TAILQ_FIRST(&pkg->p_buflist.bh_list); + mdns_buf_free(bp, &pkg->p_buflist, buf, 1); + } + + for (i = 0; i < 4; i++) { + /* Free saved pointers if any */ + if (pkg->p_data[i].offsets != NULL) + free(pkg->p_data[i].offsets); + /* Release pkg_res {} objects allocated during pkg creation */ + TAILQ_FOREACH_SAFE(pr, &pkg->p_data[i].res_head, pr_next, pr2) { + TAILQ_REMOVE(&pkg->p_data[i].res_head, pr, pr_next); + obj_free(OBJ_PKGRES, pr); + } + } + dprintf(DEBUG_STACK, "Packet pkg=%x freed (bp=%x)", pkg, bp); + obj_free(OBJ_PKG, pkg); +} + +/* * Initialize a packet chain. * A packet chain consists of one or more packets, each packet is built * using one or more buffer segments. @@ -118,95 +147,59 @@ * arg - locking argument */ void -mdns_pkgchain_init(struct mdns *md, struct mdns_pkgchain *pc, - int flags, md_lock lock, md_unlock unlock, void *arg) +mdns_pkgchain_init(struct mdns *md, struct mdns_pkgchain *pc, int flags) { - assert((lock == NULL && unlock == NULL) || (lock != unlock)); + MDNS_INIT_ASSERT(md, md_magic); pc->pc_md = md; - pc->pc_lock = lock; - pc->pc_unlock = unlock; - pc->pc_lockarg = arg; pc->pc_pkg = NULL; - pc->pc_list_len = 0; pc->pc_flags = flags; TAILQ_INIT(&pc->pc_head); MDNS_INIT_SET(pc, pc_magic); + dprintf(DEBUG_STACK, "Packet chain pc=%x initialized", pc); } /* - * Release resources allocated to a packet - */ -static inline void -free_pkg(struct mdns_packet *pkg, struct mdns_bufpool *bp) -{ - struct mdns_buf *buf; - int i; - - /* Return buffers allocated to this packet */ - while (!TAILQ_EMPTY(&pkg->p_buflist.bh_list)) { - buf = TAILQ_FIRST(&pkg->p_buflist.bh_list); - mdns_buf_free(bp, &pkg->p_buflist, buf, 1); - } - - /* Free saved pointers if any */ - for (i = 0; i < 4; i++) { - if (pkg->p_data[i].offsets != NULL) - free(pkg->p_data[i].offsets); - } - - /* Free name compression hash if any */ - if (pkg->p_nc_tbl != NULL) { - hashtbl_destroy(pkg->p_nc_tbl); - free(pkg->p_nc_tbl); - } -} - -/* * Release resources allocated to a packet chain * md - mdns handle * pc - packet chain */ void -mdns_pkgchain_free(struct mdns *md, struct mdns_pkgchain *pc) +mdns_pkgchain_free(struct mdns_pkgchain *pc) { - struct mdns_packet *pkg; - int i; + struct mdns_packet *pkg, *pkg2; MDNS_INIT_ASSERT(pc, pc_magic); - - while (!TAILQ_EMPTY(&pc->pc_head)) { - pkg = TAILQ_FIRST(&pc->pc_head); - TAILQ_REMOVE(&pc->pc_head, pkg, p_list); - free_pkg(pkg, md->md_bp); - TAILQ_INSERT_TAIL(&md->md_pkglist, pkg, p_list); - md->md_pkgfree++; + TAILQ_FOREACH_SAFE(pkg, &pc->pc_head, p_list, pkg2) { + pkg_free(pc, pkg); } - - i = (md->md_pkgfree - 1) / 2; - for (; i > 0; i--) { - pkg = TAILQ_FIRST(&md->md_pkglist); - if (pkg == NULL) - break; - TAILQ_REMOVE(&md->md_pkglist, pkg, p_list); - free(pkg); - md->md_pkgtotal--; - md->md_pkgfree--; - } - - MDNS_INIT_UNSET(pc, pc_magic); } +/* + * Return the current packet from a packet chain + */ struct mdns_packet * mdns_pkgchain_curpkg(struct mdns_pkgchain *pc) { + MDNS_INIT_ASSERT(pc, pc_magic); return (pc->pc_pkg); } /* + * Expand a chain with a new packet + */ +void +mdns_pkgchain_expand(struct mdns_pkgchain *pc) +{ + + MDNS_INIT_ASSERT(pc, pc_magic); + pkg_alloc(pc); +} + +/* * Returns a pointer to the last byte in a dns name * str - Start of dns name * end - End of buffer @@ -276,9 +269,9 @@ res = NULL; /* - * Perform a longest-sub-label match against the hash table, if a match - * is found the labels already exists within the packet and a pointer - * can be created. + * Perform a longest-sub-label match against the hash table, if a + * match is found the labels already exists within the packet and + * a pointer can be created. * As we test and miss we insert the sub-labels tested into the * hash table for further use. */ @@ -288,14 +281,14 @@ break; offset = pkg_offset; - hashtbl_add(ht, p, q - p, (void *)(int)offset, 0); + hashtbl_add(ht, p, q - p, (void *)(long)offset, 0); pkg_offset += (*p + 1); p += *p + 1; } /* A match was found, setup a pointer in `dst' and adjust length */ if (res != NULL) { - offset = 0xc000 + (int)res; + offset = 0xc000 + ((long)res & ~0xc000); MDNS_WRITE2(&dst[p - dst], htons(offset)); *dlen = p - dst + 2; } @@ -318,7 +311,7 @@ */ static int name_decompress(char *name, char *dst, size_t dstlen, char *buf, - size_t pkglen) + size_t pkglen) { char *p, *q, val; uint16_t offset; @@ -369,7 +362,8 @@ if (p == NULL) return (NULL); memcpy(p, res, 6); - error = name_decompress(res + 6, p + 6, MDNS_RECORD_LEN, buf, pkglen); + error = name_decompress(res + 6, p + 6, MDNS_RECORD_LEN, + buf, pkglen); if (error != 0) { free(p); return (NULL); @@ -400,7 +394,7 @@ /* * Labelize (and name compress) resource data that needs it */ -static inline void +static inline void res_encode(struct hashtbl *ht, char *buf, uint16_t type, char *res, size_t *rlen, int plen) { @@ -408,7 +402,7 @@ switch (type) { case mdns_in_ptr: case mdns_in_cname: - name_compress(ht, res, *rlen, buf, rlen, plen); + name_compress(ht, res, *rlen, buf, rlen, plen); break; default: memcpy(buf, res, *rlen); @@ -429,16 +423,18 @@ struct mdns_buf *buf; struct mdns_header *h; + MDNS_INIT_ASSERT(pc, pc_magic); pkg = pc->pc_pkg; if (pkg == NULL) pkg = pkg_alloc(pc); + MDNS_INIT_ASSERT(pkg, p_magic); buf = MDNS_BUFH(&pkg->p_buflist); - if (buf == NULL) + if (buf == NULL) { buf = mdns_buf_alloc(pc->pc_md->md_bp, &pkg->p_buflist, 0, 0); - - bzero(MDNS_BUF(buf), MDNS_HEADER_LEN); + bzero(MDNS_BUF(buf), MDNS_HEADER_LEN); + } pkg->p_bufseg(p_hdr) = buf; pkg->p_buf(p_hdr) = MDNS_BUF(buf); @@ -462,6 +458,8 @@ struct mdns_header *h; struct mdns_buf *buf; + MDNS_INIT_ASSERT(pkg, p_magic); + if (pkg->p_len < MDNS_HEADER_LEN) { errno = EBADMSG; return (-1); @@ -497,299 +495,517 @@ } /* - * Add a question to a packet chain - * pc - Package chain - * qs - Question set - * unicast - Unicast response desired + * Allocate a mdns_pkg_res {} object + */ +static inline struct mdns_pkg_res * +get_resource(void) +{ + struct mdns_pkg_res *pr; + + pr = obj_alloc(OBJ_PKGRES); + MDNS_INIT_SET(pr, pr_magic); + return (pr); +} + +/* + * Free a mdns_pkg_res {} object + * pr - Pointer to previously allocated object + */ +static inline void +free_resource(struct mdns_pkg_res *pr) +{ + + MDNS_INIT_UNSET(pr, pr_magic); + obj_free(OBJ_PKGRES, pr); +} + +/* + * Allocate a mdns_rrset {} object + * In reality, a mdns_pkg_res {} object is allocated and a pointer to + * its mdns_rrset member is returned. + */ +struct mdns_rrset * +mdns_pkg_getrrset(void) +{ + struct mdns_pkg_res *pr; + + pr = get_resource(); + pr->pr_what = 1; + return (&pr->pr_res.rs); +} + +/* + * Allocate a mdns_qset {} object + * In reality, a mdns_pkg_res {} object is allocated and a pointer to + * its mdns_qset member is returned. + */ +struct mdns_qset * +mdns_pkg_getqset(void) +{ + struct mdns_pkg_res *pr; + + pr = get_resource(); + pr->pr_what = 0; + return (&pr->pr_res.qs); +} + +/* + * Free a {rr,q}set obtained from mdns_pkg_get{rrset,qset} + */ +void +mdns_pkg_freeset(void *res) +{ + struct mdns_pkg_res *pr; + + pr = (struct mdns_pkg_res *)((char *)res - + (sizeof(struct mdns_pkg_res) - sizeof(pr->pr_res))); + + MDNS_INIT_ASSERT(pr, pr_magic); + free_resource(pr); +} + +/* + * Add a resource to a packet chain + * pc - Packet chain + * sec - Packet section (SEC_{QUESTIONS,AUTHORITY,ANSWERS} + * set - A pointer to either mdns_{rrset,qset} + * flags - Construction flags + * hpkg - Will be set to the packet where the header is + * + * This works as a wrapper around mdns_add_{question,answer,auth} */ -int -mdns_pkg_addquestion(struct mdns_pkgchain *pc, struct mdns_qset *qs, - int unicast) +static int +addres(struct mdns_pkgchain *pc, int sec, void *set, int flags, + struct mdns_packet **hpkg) { - char namc[MDNS_RECORD_LEN]; - struct mdns_packet *pkg, *hpkg; - struct mdns_bufpool *bp; - struct mdns_buf *buf; + struct mdns_pkg_res *pr; + struct mdns_packet *pkg; + struct mdns *md; struct mdns_header *h; - struct mdns_qsec qsec; - size_t namlen, namclen; - int i, error, flags; - uint16_t class; + size_t slen; + struct mdns_head head; + + MDNS_INIT_ASSERT(pc, pc_magic); + md = pc->pc_md; + MDNS_INIT_ASSERT(md, md_magic); - bp = pc->pc_md->md_bp; - pkg = pc->pc_pkg; - if (pkg == NULL) { - errno = EINVAL; - return (-1); + /* + * Duplicate the resource set if the duplicate flags was passed, + * this should only be done if `set' wasn't allocated using + * mdns_get_{rrset,qset}. + */ + if (flags & MDNS_PKG_DUP) { + pr = get_resource(); + if (sec == SEC_QUESTIONS) { + memcpy(&pr->pr_res.qs, (char *)set, + sizeof(struct mdns_qset)); + pr->pr_what = 0; + } + else { + memcpy(&pr->pr_res.rs, (char *)set, + sizeof(struct mdns_rrset)); + pr->pr_what = 1; + } } - - if (pkg->p_bufseg(p_questions) == NULL) { - pkg->p_bufseg(p_questions) = mdns_buf_alloc(bp, &pkg->p_buflist, 0, 0); - pkg->p_buf(p_questions) = MDNS_BUF(pkg->p_bufseg(p_questions)); + else { + pr = (struct mdns_pkg_res *)((char *)set - + (sizeof(struct mdns_pkg_res) - sizeof(pr->pr_res))); } - buf = pkg->p_bufseg(p_questions); + MDNS_INIT_ASSERT(pr, pr_magic); - namlen = strlen(qs->q_name); - i = namlen + 1 + MDNS_QSET_HLEN; + pkg = pc->pc_pkg; + if (pkg == NULL) + pkg = pkg_alloc(pc); /* - * Expand packet chains, buffer chains and buffers if needed + * This is safe as the record name is the first member of + * both mdns_rrset {} and mdns_qset {} */ - if (pc->pc_flags & MDNS_PC_CONT) { - if ((i + MDNS_BUFLEN(buf)) > MDNS_BUFSZ(buf)) { - error = mdns_buf_expand(buf, 0); - if (error != 0) + slen = pr->pr_namlen = strlen(pr->pr_res.qs.q_name); + if (pr->pr_what) + slen += MDNS_RRSET_HLEN + pr->pr_res.rs.r_datalen; + else + slen += MDNS_QSET_HLEN; + + if (!(pc->pc_flags & MDNS_PC_CONT)) { + if (pkg->p_len + slen > md->md_maxpkgsz) { + if (flags & MDNS_PKG_NOAE) { + errno = EMSGSIZE; return (-1); - pkg->p_buf(p_questions) = MDNS_BUF(buf); - } - } - else { - if (pkg->p_len + i > pc->pc_md->md_maxpkgsz) { + } h = (struct mdns_header *)pkg->p_buf(p_hdr); h->h_tc = 1; + mdns_pkg_gethdr(pkg, &head); pkg = pkg_alloc(pc); - flags = MDNS_HEAD_QUERY; - if (h->h_aa) - flags |= MDNS_HEAD_AA; - mdns_pkg_sethdr(pc, 0, flags); - buf = mdns_buf_alloc(pc->pc_md->md_bp, &pkg->p_buflist, 0, 0); - pkg->p_bufseg(p_questions) = buf; - pkg->p_buf(p_questions) = MDNS_BUF(buf); + mdns_pkg_sethdr(pc, head.h_id, head.h_flags); + + /* + * Only one resource record is allowed in + * super-sized packets, make sure the next + * record/query gets a new packet. + */ + if (pr->pr_what && pr->pr_res.rs.r_datalen > + md->md_maxpkgsz) { + pkg_alloc(pc); + mdns_pkg_sethdr(pc, head.h_id, head.h_flags); + } } - else if ((i + MDNS_BUFLEN(buf)) > MDNS_BUFSZ(buf)) { - error = mdns_buf_expand(buf, 0); - if (error != 0) - return (-1); - pkg->p_buf(p_questions) = MDNS_BUF(buf); - } + } + + TAILQ_INSERT_TAIL(&pkg->p_data[sec].res_head, pr, pr_next); + pkg->p_len += slen; + + if (pc->pc_flags & MDNS_PC_CONT) + *hpkg = TAILQ_FIRST(&pc->pc_head); + else + *hpkg = pkg; + if (*hpkg == NULL) { + mdns_pkg_sethdr(pc, 0, MDNS_HEAD_AA | + (sec == SEC_QUESTIONS ? MDNS_HEAD_QUERY : MDNS_HEAD_RESP)); + *hpkg = pkg; } + return (0); +} + +/* + * Remove a resource from a packet chain + * pc - Packet chain + * sec - Section + * hpkg - Will be set to header packet + * + */ +static struct mdns_pkg_res * +delres(struct mdns_pkgchain *pc, int sec, void *set, + struct mdns_packet **hpkg) +{ + struct mdns_pkg_res *pr; + struct mdns_packet *pkg; + size_t slen; + struct mdns_qset *qs = set; + struct mdns_rrset *rs = set; - if (pkg->p_nc_tbl == NULL) { - pkg->p_nc_tbl = malloc(sizeof(struct hashtbl)); - hashtbl_init(pkg->p_nc_tbl, 8, 256, 5); + MDNS_INIT_ASSERT(pc, pc_magic); + pkg = pc->pc_pkg; + + /* + * The fields class, type and names are identical in mdns_{qset,rrset} + */ + TAILQ_FOREACH(pr, &pkg->p_data[sec].res_head, pr_next) { + if (pr->pr_res.qs.q_class != qs->q_class || + pr->pr_res.qs.q_type != qs->q_type) + continue; + if (strncmp(pr->pr_res.qs.q_name, qs->q_name, + MDNS_RECORD_LEN) == 0) { + if (sec == SEC_QUESTIONS) + break; + if (pr->pr_res.rs.r_datalen != rs->r_datalen) + continue; + if (memcmp(pr->pr_res.rs.r_data, rs->r_data, + rs->r_datalen) == 0) + break; + } + else { + continue; + } } - namclen = MDNS_RECORD_LEN; - error = name_compress(pkg->p_nc_tbl, qs->q_name, namlen, namc, &namclen, - pkg->p_len); - if (error != 0) - return (-1); + if (pr == NULL) + return (NULL); + MDNS_INIT_ASSERT(pr, pr_magic); - memcpy(MDNS_BUFPOS(buf), namc, namlen); - MDNS_BUFLEN(buf) += namlen; + slen = pr->pr_namlen = strlen(pr->pr_res.qs.q_name); + if (pr->pr_what) + slen += MDNS_RRSET_HLEN + pr->pr_res.rs.r_datalen; + else + slen += MDNS_QSET_HLEN; - class = qs->q_class; - if (unicast) - class |= 0x8000; - qsec.qs_class = ntohs(class); - qsec.qs_type = htons(qs->q_type); + pkg->p_len -= slen; + TAILQ_REMOVE(&pkg->p_data[sec].res_head, pr, pr_next); - memcpy(MDNS_BUFPOS(buf), &qsec, sizeof(struct mdns_qsec)); - MDNS_BUFLEN(buf) += MDNS_QSET_HLEN; - pkg->p_len += MDNS_QSET_HLEN + namlen; - if (pc->pc_flags & MDNS_PC_CONT) - hpkg = TAILQ_FIRST(&pc->pc_head); + *hpkg = TAILQ_FIRST(&pc->pc_head); else - hpkg = pkg; + *hpkg = pkg; + return (pr); +} + +/* + * Adds a question to a packet chain + * pc - Packet chain + * qs - Pointer to mdns_qset {} containing construction information + * flags - Construction flags + * + * `qs' must be allocated using mdns_get_qset{}, else MDNS_PKG_DUP must + * be passed as one of the flags. + */ +int +mdns_pkg_addquestion(struct mdns_pkgchain *pc, struct mdns_qset *qs, + int flags) +{ + struct mdns_header *h; + struct mdns_packet *hpkg; + int error; - h = (struct mdns_header *)pkg->p_buf(p_hdr); + error = addres(pc, SEC_QUESTIONS, qs, flags, &hpkg); + if (error != 0) + return (error); + assert(hpkg != NULL); + h = (struct mdns_header *)hpkg->p_buf(p_hdr); h->h_qcount = htons(ntohs(h->h_qcount) + 1); - return (0); } - -int -mdns_pkg_addanswer(struct mdns_pkgchain *pc, struct mdns_rrset *rs, int flush) +/* + * Remove a question from a packet chain + * pc - Packet chain + * qs - Pointer to mdns_qset {} previsouly added + */ +struct mdns_qset * +mdns_pkg_delquestion(struct mdns_pkgchain *pc, struct mdns_qset *qs) { + struct mdns_header *h; + struct mdns_packet *hpkg; + struct mdns_pkg_res *pr; - return (addres(pc, SEC_ANSWERS, rs, flush)); + pr = delres(pc, SEC_QUESTIONS, qs, &hpkg); + if (pr == NULL) + return (NULL); + assert(hpkg != NULL); + h = (struct mdns_header *)hpkg->p_buf(p_hdr); + h->h_qcount = htons(ntohs(h->h_qcount) - 1); + return (&pr->pr_res.qs); } +/* + * Adds an authority resource to a packet chain + * pc - Packet chain + * qs - Pointer to mdns_rrset {} containing construction information + * flags - Construction flags + * + * `rs' must be allocated using mdns_get_rrset{}, else MDNS_PKG_DUP must + * be passed as one of the flags. + */ int -mdns_pkg_addauth(struct mdns_pkgchain *pc, struct mdns_rrset *rs, int flush) +mdns_pkg_addauth(struct mdns_pkgchain *pc, struct mdns_rrset *rs, + int flags) { + struct mdns_header *h; + struct mdns_packet *hpkg; + int error; - return (addres(pc, SEC_AUTHORITY, rs, flush)); + error = addres(pc, SEC_AUTHORITY, rs, flags, &hpkg); + if (error != 0) + return (error); + assert(hpkg != NULL); + h = (struct mdns_header *)hpkg->p_buf(p_hdr); + h->h_nscount = htons(ntohs(h->h_nscount) + 1); + return (0); } -int -mdns_pkg_getquestion(struct mdns_packet *pkg, int offset, struct mdns_qset *qs) +/* + * Remove an authority resource from a packet chain + * pc - Packet chain + * qs - Pointer to mdns_rrset {} previsouly added + */ +struct mdns_rrset * +mdns_pkg_delauth(struct mdns_pkgchain *pc, struct mdns_rrset *rs) { + struct mdns_header *h; + struct mdns_packet *hpkg; + struct mdns_pkg_res *pr; - return (getres(pkg, SEC_QUESTIONS, offset, (void *)qs)); + pr = delres(pc, SEC_AUTHORITY, rs, &hpkg); + if (pr == NULL) + return (NULL); + assert(hpkg != NULL); + h = (struct mdns_header *)hpkg->p_buf(p_hdr); + h->h_nscount = htons(ntohs(h->h_nscount) - 1); + return (&pr->pr_res.rs); } +/* + * Adds an answer resource to a packet chain + * pc - Packet chain + * qs - Pointer to mdns_rrsetset {} containing construction information + * flags - Construction flags + * + * `rs' must be allocated using mdns_get_rrset{}, else MDNS_PKG_DUP must + * be passed as one of the flags. + */ int -mdns_pkg_getanswer(struct mdns_packet *pkg, int offset, struct mdns_rrset *rs) +mdns_pkg_addanswer(struct mdns_pkgchain *pc, struct mdns_rrset *rs, + int flags) { + struct mdns_header *h; + struct mdns_packet *hpkg; + int error; - return (getres(pkg, SEC_ANSWERS, offset, (void *)rs)); + error = addres(pc, SEC_ANSWERS, rs, flags, &hpkg); + if (error != 0) + return (error); + assert(hpkg != NULL); + h = (struct mdns_header *)hpkg->p_buf(p_hdr); + h->h_acount = htons(ntohs(h->h_acount) + 1); + return (0); } -int -mdns_pkg_getauth(struct mdns_packet *pkg, int offset, struct mdns_rrset *rs) +/* + * Remove an answer resource from a packet chain + * pc - Packet chain + * qs - Pointer to mdns_rrset {} previsouly added + */ +struct mdns_rrset * +mdns_pkg_delanswer(struct mdns_pkgchain *pc, struct mdns_rrset *rs) { + struct mdns_header *h; + struct mdns_packet *hpkg; + struct mdns_pkg_res *pr; - return (getres(pkg, SEC_AUTHORITY, offset, (void *)rs)); + pr = delres(pc, SEC_ANSWERS, rs, &hpkg); + if (pr == NULL) + return (NULL); + assert(hpkg != NULL); + h = (struct mdns_header *)hpkg->p_buf(p_hdr); + h->h_acount = htons(ntohs(h->h_acount) - 1); + return (&pr->pr_res.rs); } >>> TRUNCATED FOR MAIL (1000 lines) <<<