PERFORCE change 123565 for review

Fredrik Lindberg fli at FreeBSD.org
Mon Jul 16 00:55:34 UTC 2007


http://perforce.freebsd.org/chv.cgi?CH=123565

Change 123565 by fli at 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 <wchar.h>
 
 #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 <errno.h>
 #include <wchar.h>
 
+#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) <<<


More information about the p4-projects mailing list