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