Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 16 Jul 2007 01:41:38 GMT
From:      Fredrik Lindberg <fli@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 123574 for review
Message-ID:  <200707160141.l6G1fcvA092417@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=123574

Change 123574 by fli@fli_nexus on 2007/07/16 01:41:33

	- Move database record structures out of mdnsd.h, they
	  live in dbrec.h now.
	- Remove thread/locking macros, they live in threads.h now.
	- Add the ability to start one-shot timers.
	- Add _wcsdup() as wcsdup only exsists in -current
	- Move query processing to its own routing and
	  bring in support for multicast responses, unicast responses
	  and legacy responses. Also add support for simultanesous
	  probe tie-breaking (although quite un-tested).
	- On the response processing side, bring in support for
	  collision detection (and defending).
	- Rename the md_if {} member mif_handle to mif_stack
	- Dump stack locking routines, the stack does its own
	  locking now.
	- Fix the -f option which allows a configuration file to be
	  specified. 
	- Initiate probe when an interface is added and on link-state change.
	- Style fixes and various minor tweaks.

Affected files ...

.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/mdnsd.c#4 edit
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/mdnsd.h#4 edit

Differences ...

==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/mdnsd.c#4 (text+ko) ====

@@ -46,6 +46,7 @@
 
 #include "mdnsd.h"
 #include "log.h"
+#include "objalloc.h"
 
 int bufpool_lock(void *);
 int bufpool_unlock(void *);
@@ -66,8 +67,6 @@
 int evh_routesock_init(int, struct event_io *, ev_arg);
 int evh_routesock(struct event_io *, ev_arg);
 
-int tmr_start(struct md_glob *, uint32_t, ev_handler_tmr, void *);
-void tmr_stop(struct md_glob *, int);
 static int evh_cacheclean(const struct event_tmr *, const ev_arg);
 
 static void usage(char *);
@@ -89,20 +88,39 @@
 	return (0);
 }
 
+static int
+tmr_init_oneshot(int what, struct event_tmr *ev, ev_arg arg)
+{
+
+	switch (what) {
+	case EVENT_INIT_OPEN:
+		ev->evtmr_timeout = arg.int32;
+		ev->evtmr_oneshot = 1;
+		break;
+	case EVENT_INIT_CLOSE:
+		break;
+	}
+	return (0);
+}
+
 /*
  * Start a timer, returns a unique timer identifier
  */
 int
 tmr_start(struct md_glob *g, uint32_t timeout, ev_handler_tmr handler,
-    void *arg)
+    void *arg, int oneshot)
 {
 	int id;
 	ev_arg eva, evai;
 
 	evai.int32 = timeout;
 	eva.ptr = arg;
-	id = event_add(g->g_evl, EVENT_TYPE_TMR, handler, &eva,
-		tmr_init, &evai);
+	if (oneshot)
+		id = event_add(g->g_evl, EVENT_TYPE_TMR, handler, &eva,
+		    tmr_init_oneshot, &evai);
+	else
+		id = event_add(g->g_evl, EVENT_TYPE_TMR, handler, &eva,
+		    tmr_init, &evai);
 	return (id);
 }
 
@@ -126,6 +144,7 @@
 	TAILQ_FOREACH(mif, &g->g_ifs, mif_next) {
 		if (if_aquire(mif, 1) != 0)
 			continue;
+	
 		cache_clean(&mif->mif_cache);	
 		if_release(mif, 1);
 	}
@@ -151,12 +170,14 @@
 		mif->mif_flags &= ~MIF_LINKUP;
 		cache_destroy(&mif->mif_cache);
 		cache_init(&mif->mif_cache);
-		dprintf(DEBUG_MISC, "Link state change to DOWN on %s", mif->mif_ifnam);
+		dprintf(DEBUG_MISC, "Link state change to DOWN on %s",
+		    mif->mif_ifnam);
 	}
 	else {
 		mif->mif_flags |= MIF_LINKUP;
-		/* TODO: call verify unique records */
-		dprintf(DEBUG_MISC, "Link state change to UP on %s", mif->mif_ifnam);
+		dprintf(DEBUG_MISC, "Link state change to UP on %s",
+		    mif->mif_ifnam);
+		dbr_probe_all(&mif->mif_dbr);
 	}
 	if_release(mif, 1);
 	return (0);
@@ -186,6 +207,25 @@
 }
 
 /*
+ * Duplicate an wide character string
+ * XXX: Move to a better place
+ */
+wchar_t *
+_wcsdup(const wchar_t *s)
+{
+	size_t len;
+	wchar_t *d;
+
+	len = (wcslen(s) + 1) * sizeof(wchar_t);
+	d = malloc(len);
+	if (d == NULL)
+		return (NULL);
+	memcpy(d, s, len);
+	return (d);
+}
+
+
+/*
  * Generic I/O read-ready event initializtion
  */
 int
@@ -204,7 +244,280 @@
 	return (0);
 }
 
+static inline void
+record2rrset(struct record *r, struct record_type *rt, struct record_res *rr,
+    struct mdns_rrset *rs, int cflush)
+{
+
+	MDNS_INIT_ASSERT(r, r_magic);
+	MDNS_INIT_ASSERT(rt, rt_magic);
+	MDNS_INIT_ASSERT(rr, rr_magic);
+
+	mdns_rrset_name(rs, r->r_name);
+	rs->r_type = rt->rt_type;
+	rs->r_class = mdns_c_in;
+	rs->r_cflush = cflush;
+	rs->r_datalen = rr->rr_len;
+	rs->r_data = rr->rr_data;
+}
+
+/*
+ * Callback routine from aggregation queue, called when a data
+ * object is supposed to be added to the packet.
+ */
+static void
+aggr_resp_engine(struct mdns_pkgchain *pc, void *data)
+{
+	struct record *r;
+	struct record_type *rt;
+	struct record_res *rr;
+	struct dbr_res *ds;
+	struct mdns_rrset *mrs;
+
+	rr = data;
+	MDNS_INIT_ASSERT(rr, rr_magic);
+	ds = record_res_getparent(rr);
+	MDNS_INIT_ASSERT(ds, ds_magic);
+	rt = rr->rr_type;
+	MDNS_INIT_ASSERT(rt, rt_magic);
+	r = rt->rt_record;
+	MDNS_INIT_ASSERT(r, r_magic);
+
+	mrs = mdns_pkg_getrrset();
+	record2rrset(r, rt, rr, mrs, 0);
+	mrs->r_ttl = ds->ds_ttl;
+	clock_gettime(CLOCK_REALTIME, &ds->ds_time);
+	mdns_pkg_addanswer(pc, mrs, 0);
+}
+
+/*
+ * Initialize a response packet chain
+ */
+static void
+aggr_resp_pkgchain(struct md_if *mif, struct mdns_pkgchain *pc)
+{
+
+	mdns_pkgchain_init(&mif->mif_stack, pc, MDNS_PC_NONE);
+	mdns_pkg_sethdr(pc, 0, MDNS_HEAD_RESP | MDNS_HEAD_AA);
+}
+
 /*
+ * Process a query packet
+ */
+static void
+process_query(struct md_if *mif, struct mdns_packet *pkg,
+    struct mdns_head *hdr, struct sockaddr *from, socklen_t fromlen, int legacy)
+{
+	struct mdns_qset qs;
+	struct mdns_rrset rs, *rsp;
+	struct dbr_rec *dr;
+	struct dbr_res *ds;
+	struct cache_res *cr;
+	struct record_res  *rr;
+	struct record_type *rt;
+	struct record *r;
+	int i, error, send_unicast;
+	time_t min, min2, max;
+	struct aqueue *aq;
+	struct timespec ts;
+	struct cache ac;
+	struct records auth;
+	struct mdns_pkgchain upc;
+
+	clock_gettime(CLOCK_REALTIME, &ts);
+
+	mdns_pkgchain_init(&mif->mif_stack, &upc, MDNS_PC_NONE);
+	mdns_pkg_sethdr(&upc, hdr->h_id, MDNS_HEAD_RESP | MDNS_HEAD_AA);
+	send_unicast = 0;
+	if (from->sa_family == AF_INET)
+		aq = &mif->mif_aq4;
+#ifdef INET6
+	else if (from->sa_family == AF_INET6)
+		aq = &mif->mif_aq6;
+#endif
+
+	/*
+	 * Process the answer section first
+	 */
+	if (hdr->h_canswer > 0)
+		cache_init(&ac);
+	for (i = 0; i < hdr->h_canswer; i++) {
+		error = mdns_pkg_getanswer(pkg, i, &rs);
+		if (error != 0)
+			break;
+		if (rs.r_class != mdns_c_in) {
+			free(rs.r_data);
+			continue;
+		}
+
+		/*
+		 * Check if this is a resource we might respond to.
+		 * If it is, check if it's on the output queue and
+		 * remove it if TTL rules match, otherwise add it
+		 * to answer suppression lookup cache.
+		 */
+		ds = dbr_find_res(&mif->mif_dbr, rs.r_name, rs.r_type,
+		    rs.r_data, rs.r_datalen);
+		if (ds != NULL && !(ds->ds_flags & DS_INVALID)) {
+			rr = &ds->ds_res;
+			if (aq_inqueue(aq, rr)) {
+				if (rs.r_ttl > ds->ds_ttl / 2)
+					aq_dequeue(aq, rr);
+			}
+			else if (rs.r_ttl > ds->ds_ttl / 2) {
+				error = cache_add(&ac, &rs, NULL);
+				if (error == 1)
+					free(rs.r_data);
+			}
+			else
+				free(rs.r_data);
+		}
+		else {
+			free(rs.r_data);
+		}
+	}
+
+	/*
+	 * Process the authority section, data in here is used
+	 * for probe tie breaking.
+	 */
+	if (hdr->h_cauth > 0)
+		records_init(&auth, mdns_c_in);
+	for (i = 0; i < hdr->h_cauth; i++) {
+		error = mdns_pkg_getauth(pkg, i, &rs);
+		if (error != 0)
+			break;
+		if (rs.r_class != mdns_c_in) {
+			free(rs.r_data);
+			continue;
+		}
+		record_get(&auth, &r, 0, rs.r_name);
+		record_res_add(r, &rr, 0, rs.r_type,
+		    rs.r_data, rs.r_datalen);
+	}
+
+	/*
+	 * TC bit set, min 400-500 ms delay
+	 * Questions > 1, min 20-120 ms delay
+	 * Other, 0 ms
+	 */
+	if (hdr->h_flags & MDNS_HEAD_TC)
+		min2 = (random() % 101) + 400;
+	else if (hdr->h_cquestion > 1)
+		min2 = (random() % 101) + 20;
+	else
+		min = 0;
+
+	/*
+	 * Process the question section
+	 */
+	for (i = 0; i < hdr->h_cquestion; i++) {
+		error = mdns_pkg_getquestion(pkg, i, &qs);
+		if (error != 0)
+			break;
+		if (qs.q_class != mdns_c_in)
+			continue;
+
+		dprintf(DEBUG_RECV,
+		    "question for %s, type=%d, unicast=%d, legacy=%d",
+		    qs.q_name, qs.q_type, qs.q_unicast, legacy);
+
+		dr = dbr_find(&mif->mif_dbr, qs.q_name);
+		if (dr == NULL)
+			continue;
+		MDNS_INIT_ASSERT(dr, dr_magic);
+		/*
+		 * Simultanesous probe tie-breaking
+		 */
+		if (dr->dr_flags & DR_PROBING && hdr->h_cauth > 0) {
+			record_get(&auth, &r, RECORD_NOINIT, qs.q_name);
+			dbr_tiebreak(&mif->mif_dbr, dr, r);
+			continue;	
+		}
+		else if (!(dr->dr_flags & DR_OK)) {
+			dprintf(DEBUG_SEND, "Record %s found in "
+			    "database, but is not marked ok (%x)",
+			    qs.q_name, dr->dr_flags);
+			continue;
+		}
+		/*
+		 * Fix delay time for if this record is
+		 * marked as shared
+		 */
+		else if (dr->dr_flags & DR_SHARED && min2 == 0)
+			min = (random() % 101) + 20;
+		else
+			min = min2;
+
+		/* Allow additional 500ms if aggreation is possible */
+		max = min + 500;
+
+		dprintf(DEBUG_SEND, "Found %s in database, responding",
+		    qs.q_name);
+		if (legacy)
+			mdns_pkg_addquestion(&upc, &qs, MDNS_PKG_DUP);
+
+		r = &dr->dr_rec;
+		record_foreach(rt, r) {
+			if (qs.q_type != rt->rt_type
+			    && qs.q_type != mdns_in_any)
+				continue;
+			record_type_foreach(rr, rt) {
+				ds = record_res_getparent(rr);
+				if (ds->ds_flags & DS_INVALID)
+					continue;
+				if (hdr->h_canswer > 0) {
+					cr = cache_find(&ac, qs.q_name,
+					    qs.q_type);
+					if (cr != NULL)
+						continue;
+				}
+				/*
+				 * This clients needs/wants a unicast response,
+				 * we also schedule a multicast response in we
+				 * this resource hasn't been multicasted
+				 * "recently".
+				 */
+				if (legacy || qs.q_unicast) {
+					rsp = mdns_pkg_getrrset();
+					record2rrset(r, rt, rr, rsp, 0);
+					rsp->r_ttl = legacy ? 10 : ds->ds_ttl;
+					mdns_pkg_addanswer(&upc, rsp, 0);
+					send_unicast = 1;
+					/*
+					 * Schedule a multicast response if
+					 * the time this resource last was
+					 * sent is greater than a quarter of
+					 * its ttl.
+					 */	
+					if ((ts.tv_sec - ds->ds_time.tv_sec) >
+					    (int32_t)(ds->ds_ttl / 4))
+						aq_enqueue(aq, rr, min, max);
+				}
+				/*
+				 * Multicase response, only if not already in
+				 * aggregation queue and it's at least one
+				 * second since we last sent this resource.
+				 */
+				else if (!aq_inqueue(aq, rr) &&
+				    ts.tv_sec > ds->ds_time.tv_sec)
+					aq_enqueue(aq, rr, min, max);
+			}
+		}
+	}
+
+	if (send_unicast)
+		oq_enqueue(&mif->mif_oq, &upc, from->sa_family,
+		    from, fromlen);
+	if (hdr->h_canswer > 0)
+		cache_destroy(&ac);
+	if (hdr->h_cauth > 0)
+		records_destroy(&auth);
+
+	mdns_pkgchain_free(&upc);
+}
+
+/*
  * Process a mdns packet and generate appropriate responses
  *   mif  - Interface handle
  *   pc   - Packet chain
@@ -213,64 +526,99 @@
  *   fromlen - Socket address length
  */
 static int
-pkgprocess(struct md_if *mif, struct mdns_pkgchain *pc, int type,
+pkgprocess(struct md_if *mif, struct mdns_pkgchain *pc, int type __unused,
 	struct sockaddr *from, socklen_t fromlen)
 {
 	struct mdns_packet *pkg;
+	struct mdns_head hdr;
 	struct mdns_rrset rs;
-	struct mdns_qset qs;
-	struct mdns_head hdr;
-	int i, error;
+	struct dbr_rec *dr;
+	int i, error, sinaddr_len, legacy;
+	in_port_t port;
+	void *sinaddr = NULL;
+	struct sockaddr_in *sin;
+#ifdef INET6
+	struct sockaddr_in6 *sin6;
+#endif
 #ifdef DEBUG
 	char addr[SOCK_MAXADDRLEN+1];
-	void *sinaddr = NULL;
+#endif
+	struct aqueue *aq;
 
 	switch (from->sa_family) {
 	case AF_INET:
+		sin = (struct sockaddr_in *)from;
+		port = sin->sin_port;
 		sinaddr = &((struct sockaddr_in *)from)->sin_addr;
+		sinaddr_len = sizeof(struct in_addr);
+		aq = &mif->mif_aq4;
 		break;
 #ifdef INET6
 	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)from;
+		port = sin6->sin6_port;
 		sinaddr = &((struct sockaddr_in6 *)from)->sin6_addr;
+		sinaddr_len = sizeof(struct in6_addr);
+		aq = &mif->mif_aq6;
 		break;
 #endif /* INET6 */
 	}
+
+#ifdef DEBUG
 	inet_ntop(from->sa_family, sinaddr, addr, SOCK_MAXADDRLEN);
-	dprintf(DEBUG_RECV, "Packet received peer=%s, if=%s", addr, mif->mif_ifnam);
+	dprintf(DEBUG_RECV, "Packet received peer=%s, port=%d, if=%s",
+	    addr, port, mif->mif_ifnam);
 #endif /* DEBUG */
 
 	pkg = mdns_pkgchain_curpkg(pc);
 	mdns_pkg_gethdr(pkg, &hdr);
-	dprintf(DEBUG_RECV, "questions=%d, answers=%d, authority=%d",
+	dprintf(DEBUG_RECV, "type=%s, questions=%d, answers=%d, authority=%d",
+	    hdr.h_flags & MDNS_HEAD_QUERY ? "query" : "resp",
 	    hdr.h_cquestion, hdr.h_canswer, hdr.h_cauth);
 
+	/*
+	 * We are processing a query
+	 */
 	if (hdr.h_flags & MDNS_HEAD_QUERY) {
-		for (i = 0; i < hdr.h_cquestion; i++) {
-			error = mdns_pkg_getquestion(pkg, i, &qs);
-			if (error != 0)
-				break;
+		legacy = (port != 5353) ? 1 : 0;
+		process_query(mif, pkg, &hdr, from, fromlen, legacy);
+	}
 
-			/* TODO: check db and reply. Do not reply if answer is
-			in answer section with ttl > own ttl/2 */
-		}
-	}
+	/*
+	 * We are processing a response
+	 */
 	else if (hdr.h_flags & MDNS_HEAD_RESP) {
+
 		for (i = 0; i < hdr.h_canswer; i++) {
 			error = mdns_pkg_getanswer(pkg, i, &rs);
 			if (error != 0)
 				break;
-			/* TODO: check db for conflicts */
+			if (rs.r_class != mdns_c_in) {
+				free(rs.r_data);
+				continue;
+			}
+
+			dr = dbr_find(&mif->mif_dbr, rs.r_name);
+			if (dr != NULL && !(dr->dr_flags & DR_SHARED)) {
+				dprintf(DEBUG_SEND, "Conflicting name %s "
+				    "with peer %s", rs.r_name, addr);
+				dbr_defend(&mif->mif_dbr, dr, &rs,
+				    from->sa_family);
+				continue;
+			}
+
+
 			/* TODO: check for waiting clients */
 			/* TODO: check for pending questions matching this */
 			/* TODO: check for pending answers matching this */
 
 			/*
-			 * Purge records older than 1 second if this is supposed to
-			 * be a uniqe rrset (cache flush bit set)
+			 * Purge records older than 1 second if this is
+			 * supposed to be a unique rrset (cache flush bit set)
 			 */
 			if (rs.r_cflush)
-				cache_purge(&mif->mif_cache, 1, rs.r_name, rs.r_type);
-
+				cache_purge(&mif->mif_cache, 1, rs.r_name,
+				    rs.r_type);
 			error = cache_add(&mif->mif_cache, &rs, NULL);
 			if (error == 1)
 				free(rs.r_data);
@@ -313,14 +661,13 @@
 	 * Initialize a packet chain, receive the packet and hand it to the
 	 * packet processor.
 	 */
-	mdns_pkgchain_init(&mif->mif_handle, &pc, MDNS_PC_NONE, stack_lock,
-		stack_unlock, mif);
+	mdns_pkgchain_init(&mif->mif_stack, &pc, MDNS_PC_NONE);
 
-	n = mdns_recv(&mif->mif_handle, &pc, sa.sa_family, saptr, &salen);
+	n = mdns_recv(&mif->mif_stack, &pc, sa.sa_family, saptr, &salen);
 	if (n <= 0) {
 		if (n == 0) {
-			dprintf(DEBUG_RECV, "No data on UDP socket sock=%d, mif=%x",
-			    fd, mif);
+			dprintf(DEBUG_RECV,
+			    "No data on UDP socket sock=%d, mif=%x", fd, mif);
 		}
 		error = -1;
 		goto out;
@@ -330,7 +677,7 @@
 	error = pkgprocess(mif, &pc, MDNS_UDP, saptr, salen);
 
 out:
-	mdns_pkgchain_free(&mif->mif_handle, &pc);
+	mdns_pkgchain_free(&pc);
 	if_release(mif, 0);
 	return (error);
 }
@@ -354,7 +701,7 @@
 #endif
 
 	fd = ev->evio_fd;
-	sock = mdns_tcp_client(&mif->mif_handle, fd, &sa, &salen);
+	sock = mdns_tcp_client(&mif->mif_stack, fd, &sa, &salen);
 	if (sock < 0)
 		return (0);
 
@@ -406,14 +753,13 @@
 	if (if_aquire(mif, 0) != 0)
 		return (-1);
 
-	mdns_pkgchain_init(&mif->mif_handle, &pc, MDNS_PC_CONT, stack_lock,
-		stack_unlock, mif);
+	mdns_pkgchain_init(&mif->mif_stack, &pc, MDNS_PC_CONT);
 
-	n = mdns_tcp_recv(&mif->mif_handle, fd, &pc);
+	n = mdns_tcp_recv(&mif->mif_stack, fd, &pc);
 	if (n <= 0) {
 		if (n == 0) {
-			dprintf(DEBUG_RECV, "No data on TCP socket sock=%d, mif=%x",
-			    fd, mif);
+			dprintf(DEBUG_RECV,
+			    "No data on TCP socket sock=%d, mif=%x", fd, mif);
 		}
 		error = -1;
 		goto out;
@@ -426,43 +772,12 @@
 	error = pkgprocess(mif, &pc, MDNS_TCP, &sa, salen);
 
 out:
-	mdns_pkgchain_free(&mif->mif_handle, &pc);
+	mdns_pkgchain_free(&pc);
 	if_release(mif, 0);
 	return (error);
 }
 
 /*
- * Aquire interface write lock, read lock should be held
- * Called from mdns stack during packet allocation.
- */
-int
-stack_lock(void *arg)
-{
-	struct md_if *mif;
-
-	mif = (struct md_if *)arg;
-	if_release(mif, 0);
-	if_aquire(mif, 1);
-	return (0);	
-}
-
-/*
- * Downgrade write lock to read lock
- * Called from mdns stack after packet allocation.
- */
-int
-stack_unlock(void *arg)
-{
-	struct md_if *mif;
-
-	mif = (struct md_if *)arg;	
-	if_release(mif, 1);
-	if_aquire(mif, 0);
-	return (0);	
-}
-
-
-/*
  * Buffer pool lock
  * Called from mdns stack during buffer pool allocations
  */
@@ -550,15 +865,15 @@
 	g = mif->mif_glob;
 	eva.ptr = mif;
 	/* Open up UDP and TCP INET sockets */
-	error = mdns_open(&mif->mif_handle, MDNS_UDP, PF_INET);
+	error = mdns_open(&mif->mif_stack, MDNS_UDP, PF_INET);
 	if (error == 0)
 		mif->mif_flags |= MIF_UDP4;
-	error = mdns_open(&mif->mif_handle, MDNS_TCP, PF_INET);
+	error = mdns_open(&mif->mif_stack, MDNS_TCP, PF_INET);
 	if (error == 0)
 		mif->mif_flags |= MIF_TCP4;
 
 	/* Install read-ready event to UDP INET socket */
-	socks = mdns_get_sock(&mif->mif_handle, MDNS_UDP, PF_INET, &socklen);    	
+	socks = mdns_get_sock(&mif->mif_stack, MDNS_UDP, PF_INET, &socklen);    	
 	if (socklen == 1) {
 		evai.fd = socks[0];
 		error = event_add(g->g_evl, EVENT_TYPE_IO, evh_udp_recv, &eva,
@@ -567,37 +882,39 @@
 			ADD2EVLIST(mif, error);
 		}
 		else {
-			dprintf(DEBUG_EVENT, "Failed to add read event for UDP (INET)");
+			dprintf(DEBUG_EVENT,
+			    "Failed to add read event for UDP (INET)");
 		}
 	}
 
 	/* Install read-ready event to TCP INET socket */
-	socks = mdns_get_sock(&mif->mif_handle, MDNS_TCP, PF_INET, &socklen);    	
+	socks = mdns_get_sock(&mif->mif_stack, MDNS_TCP, PF_INET, &socklen);    	
 	if (socklen > 0) {
 		for (i = 0; i < socklen; i++) {
 			evai.fd = socks[i];
-			error = event_add(g->g_evl, EVENT_TYPE_IO, evh_tcpcli, &eva,
-			    evh_ioread_init, &evai);
+			error = event_add(g->g_evl, EVENT_TYPE_IO, evh_tcpcli,
+			    &eva, evh_ioread_init, &evai);
 			if (error >= 0) {
 				ADD2EVLIST(mif, error);
 			}
 			else {
-				dprintf(DEBUG_EVENT, "Failed to add read event to TCP (INET)");
+				dprintf(DEBUG_EVENT,
+				    "Failed to add read event to TCP (INET)");
 			}
 		}
 	}
 
 #ifdef INET6
 	/* Open up UDP and TCP INET6 sockets */
-	error = mdns_open(&mif->mif_handle, MDNS_UDP, PF_INET6);
+	error = mdns_open(&mif->mif_stack, MDNS_UDP, PF_INET6);
 	if (error == 0)
 		mif->mif_flags |= MIF_UDP6;
-	error = mdns_open(&mif->mif_handle, MDNS_TCP, PF_INET6);
+	error = mdns_open(&mif->mif_stack, MDNS_TCP, PF_INET6);
 	if (error == 0)
 		mif->mif_flags |= MIF_TCP6;
 
 	/* Install read-ready event to UDP INET6 socket */
-	socks = mdns_get_sock(&mif->mif_handle, MDNS_UDP, PF_INET6, &socklen);    	
+	socks = mdns_get_sock(&mif->mif_stack, MDNS_UDP, PF_INET6, &socklen);    	
 	if (socklen == 1) {
 		evai.fd = socks[0];
 		error = event_add(g->g_evl, EVENT_TYPE_IO, evh_udp_recv, &eva,
@@ -606,22 +923,24 @@
 			ADD2EVLIST(mif, error);
 		}
 		else {
-			dprintf(DEBUG_EVENT, "Failed to add read event for UDP (INET6)");
+			dprintf(DEBUG_EVENT,
+			    "Failed to add read event for UDP (INET6)");
 		}
 	}
 
 	/* Install read-ready event to TCP INET6 socket */
-	socks = mdns_get_sock(&mif->mif_handle, MDNS_TCP, PF_INET6, &socklen);    	
+	socks = mdns_get_sock(&mif->mif_stack, MDNS_TCP, PF_INET6, &socklen);    	
 	if (socklen > 0) {
 		for (i = 0; i < socklen; i++) {
 			evai.fd = socks[i];
-			error = event_add(g->g_evl, EVENT_TYPE_IO, evh_tcpcli, &eva,
-			    evh_ioread_init, &evai);
+			error = event_add(g->g_evl, EVENT_TYPE_IO, evh_tcpcli,
+			    &eva, evh_ioread_init, &evai);
 			if (error >= 0) {
 				ADD2EVLIST(mif, error);
 			}
 			else {
-				dprintf(DEBUG_EVENT, "Failed to add read event to TCP (INET6)");
+				dprintf(DEBUG_EVENT,
+				    "Failed to add read event to TCP (INET6)");
 			}
 		}
 	}
@@ -660,7 +979,6 @@
 	return (LINK_STATE_UNKNOWN);
 }
 
-
 /*
  * Allocate a new interface
  */
@@ -669,35 +987,57 @@
 {
 	struct md_if *mif;
 	int error;
+	struct aq_func aqf;
 
 	mif = malloc(sizeof(struct md_if));
 	if (mif == NULL)
 		return (NULL);
 	bzero(mif, sizeof(struct md_if));
+	MDNS_INIT_SET(mif, mif_magic);
 	mif->mif_index = if_nametoindex(ifnam);
 	if (mif->mif_index == 0)
 		goto out;
 	strncpy(mif->mif_ifnam, ifnam, IFNAMSIZ);
 
 	/* Initialize low-level mdns stack on this interface */
-	error = mdns_init(&mif->mif_handle, g->g_bp, ifnam);
+	error = mdns_init(&mif->mif_stack, g->g_bp, ifnam);
 	if (error != 0)
 		goto out;
+	MTX_INIT(mif, mif_stack_mtx, NULL);
 
 	RW_INIT(mif, mif_lock, NULL);	
 	RW_WLOCK(mif, mif_lock);
 	mif->mif_glob = g;
 	TAILQ_INIT(&mif->mif_evlist);
-	
+	if (get_linkstatus(ifnam) != LINK_STATE_DOWN)
+		mif->mif_flags |= MIF_LINKUP;
+
+	/* Initialize cache */	
 	cache_init(&mif->mif_cache);
 
-	if (get_linkstatus(ifnam) != LINK_STATE_DOWN)
-		mif->mif_flags |= MIF_LINKUP;
+	/* Initialize output queue */
+	oq_init(&mif->mif_oq, mif);
+
+	/* Initialize multicast aggregation queues */
+	aqf.aqf_engine = aggr_resp_engine;
+	aqf.aqf_pcinit = aggr_resp_pkgchain;
+	aqf.aqf_enqueue = aqf.aqf_dequeue = NULL;
+	aq_init(&mif->mif_aq4, &mif->mif_oq, &aqf, AF_INET, NULL, 0);
+#ifdef INET6
+	aq_init(&mif->mif_aq6, &mif->mif_oq, &aqf, AF_INET6, NULL, 0);
+#endif
+
+	/* Initialize self-claimed record database */
+	dbr_init(&mif->mif_dbr, mif);
+
+	/* Bring up sockets, at this point we might receive packets */
 	setup_socks(mif);
 
-	MDNS_INIT_SET(mif, mif_magic);
-	dbr_init(&mif->mif_dbr, mif);
-	cfg_read(&mif->mif_dbr, ifnam, "mdnsd.conf");
+	/*
+	 * Read configuration file and create self-claimed records.
+	 * This is done after socket setup so probing is safe to start.
+	 */
+	cfg_read(&mif->mif_dbr, ifnam, g->g_cfgfile);
 
 	RW_WLOCK(g, g_lock);
 	TAILQ_INSERT_TAIL(&g->g_ifs, mif, mif_next);
@@ -706,6 +1046,8 @@
 	RW_UNLOCK(mif, mif_lock);
 	logger(LOG_NOTICE, "Added interface %s", mif->mif_ifnam);
 
+	dbr_probe_all(&mif->mif_dbr);
+
 	return (mif);
 out:
 	free(mif);
@@ -735,7 +1077,13 @@
 		free(ifev);
 	}
 
-	mdns_destroy(&mif->mif_handle);
+	aq_destroy(&mif->mif_aq4);
+#ifdef INET6
+	aq_destroy(&mif->mif_aq6);
+#endif
+	oq_destroy(&mif->mif_oq);
+
+	mdns_destroy(&mif->mif_stack);
 	cache_destroy(&mif->mif_cache);
 	dbr_destroy(&mif->mif_dbr);
 
@@ -780,6 +1128,71 @@
 	return (0);
 }
 
+static inline void
+ifevent(struct md_glob *g, struct if_msghdr *ifm)
+{
+	struct md_if *mif;
+	struct md_if_ev *ifev, *ifev2;
+	char ifnam[IFNAMSIZ];
+
+	RW_RLOCK(g, g_lock);
+	mif = if_indextodata(g, ifm->ifm_index);
+	RW_UNLOCK(g, g_lock);
+
+	if (ifm->ifm_type == RTM_IFINFO) {
+		if ((ifm->ifm_flags & (IFF_UP | IFF_MULTICAST)) ==
+		    (IFF_UP | IFF_MULTICAST) && mif == NULL) {
+			if (if_indextoname(ifm->ifm_index, ifnam) != NULL)
+				if_new(g, ifnam);
+		}
+		else if (!(ifm->ifm_flags & IFF_UP) && mif != NULL) {
+			if_del(g, mif);
+		}
+		else {
+			if (if_aquire(mif, 1) != 0)
+				return;
+
+			if (mif->mif_flags & MIF_LINKCHG) {
+				tmr_stop(g, mif->mif_tmr);
+				mif->mif_flags &= ~MIF_LINKCHG;
+				dprintf(DEBUG_MISC, "Link on %s restored, "
+				    "ignoring state change", mif->mif_ifnam);
+			}
+			else if ((ifm->ifm_data.ifi_link_state ==
+			    LINK_STATE_UP &&
+			    !(mif->mif_flags & MIF_LINKUP)) ||
+			    (ifm->ifm_data.ifi_link_state == LINK_STATE_DOWN &&
+			    mif->mif_flags & MIF_LINKUP)) {
+				mif->mif_flags |= MIF_LINKCHG;
+				mif->mif_tmr = tmr_start(g, 3000, evh_linkchg,
+				    mif, 0);
+			}
+			if_release(mif, 1);
+		}
+	}
+
+	if (mif == NULL)
+		return;
+
+	if (ifm->ifm_type == RTM_DELADDR || ifm->ifm_type == RTM_NEWADDR) {
+		if_aquire(mif, 1);
+		TAILQ_FOREACH_SAFE(ifev, &mif->mif_evlist, ifev_next, ifev2) {
+			event_del(g->g_evl, ifev->ifev_id, NULL);
+			TAILQ_REMOVE(&mif->mif_evlist, ifev, ifev_next);
+			free(ifev);
+		}
+		mdns_close(&mif->mif_stack, MDNS_UDP, PF_INET);
+		mdns_close(&mif->mif_stack, MDNS_TCP, PF_INET);
+#ifdef INET6
+		mdns_close(&mif->mif_stack, MDNS_UDP, PF_INET6);
+		mdns_close(&mif->mif_stack, MDNS_TCP, PF_INET6);
+#endif
+		mif->mif_flags &= ~(MIF_UDP4 | MIF_TCP4 | MIF_UDP6 | MIF_TCP6);
+		setup_socks(mif);
+		if_release(mif, 1);
+	}
+}
+
 /*
  * Routing socket event handler
  * This will monitor a routing socket and add/remove interfaces as
@@ -790,12 +1203,10 @@
 {
 #define RS_BUFLEN (sizeof(struct rt_msghdr) + 512)
 	struct md_glob *g = (struct md_glob *)arg.ptr;
-	struct md_if *mif;
 	struct if_msghdr *ifm;
 	int len, sock;
 	char *next, *lim;
-	struct md_if_ev *ifev, *ifev2;
-	char buf[RS_BUFLEN], ifnam[IFNAMSIZ];
+	char buf[RS_BUFLEN];
 
 	sock = ev->evio_fd;
 
@@ -808,65 +1219,7 @@
 			ifm = (struct if_msghdr *) next;
 			if (ifm->ifm_flags & IFF_LOOPBACK)
 				continue;
-
-			RW_RLOCK(g, g_lock);
-			mif = if_indextodata(g, ifm->ifm_index);
-			RW_UNLOCK(g, g_lock);
-
-			if (ifm->ifm_type == RTM_IFINFO) {
-				if (ifm->ifm_flags & IFF_UP && mif == NULL) {
-					if (ifm->ifm_flags & IFF_MULTICAST)
-						if (if_indextoname(ifm->ifm_index, ifnam) != NULL)
-							if_new(g, ifnam);
-				}
-				else if (!(ifm->ifm_flags & IFF_UP) && mif != NULL) {
-					if_del(g, mif);
-				}
-				else {
-					if (if_aquire(mif, 1) != 0)
-						continue;
-
-					if (mif->mif_flags & MIF_LINKCHG) {
-						tmr_stop(g, mif->mif_tmr);
-						mif->mif_flags &= ~MIF_LINKCHG;
-						dprintf(DEBUG_MISC,
-					        "Link on %s re-restored, ignoring state change",
-					        mif->mif_ifnam);
-					}
-					else if ((ifm->ifm_data.ifi_link_state == LINK_STATE_UP &&
-				    	!(mif->mif_flags & MIF_LINKUP)) ||
-				    	(ifm->ifm_data.ifi_link_state == LINK_STATE_DOWN &&
-				    	mif->mif_flags & MIF_LINKUP)) {
-						mif->mif_flags |= MIF_LINKCHG;
-						mif->mif_tmr = tmr_start(g, 3000, evh_linkchg, mif);
-					}
-					if_release(mif, 1);
-				}
-			}
-
-			if (mif == NULL) {
-				continue;
-			}
-
-			if_aquire(mif, 1);
-			if (ifm->ifm_type == RTM_DELADDR) {
-				TAILQ_FOREACH_SAFE(ifev, &mif->mif_evlist, ifev_next, ifev2) {
-					event_del(g->g_evl, ifev->ifev_id, NULL);
-					TAILQ_REMOVE(&mif->mif_evlist, ifev, ifev_next);
-					free(ifev);
-				}
-				mdns_close(&mif->mif_handle, MDNS_UDP, PF_INET);
-				mdns_close(&mif->mif_handle, MDNS_TCP, PF_INET);
-#ifdef INET6
-				mdns_close(&mif->mif_handle, MDNS_UDP, PF_INET6);
-				mdns_close(&mif->mif_handle, MDNS_TCP, PF_INET6);
-#endif
-				mif->mif_flags &= ~(MIF_UDP4 | MIF_TCP4 | MIF_UDP6 | MIF_TCP6);
-			}
-			else if (ifm->ifm_type == RTM_NEWADDR) {
-				setup_socks(mif);
-			}
-			if_release(mif, 1);
+			ifevent(g, ifm);
 		}
 	}
 
@@ -912,6 +1265,7 @@
 	RW_INIT(&glob, g_lock, NULL);
 	MTX_INIT(&glob, g_bp_mtx, NULL);
 	TAILQ_INIT(&glob.g_ifs);
+	glob.g_cfgfile = cfgfile != NULL ? cfgfile : strdup(DEFAULT_CFGFILE);
 
 	/* Initialize logging */
 	log_init(!nodaemon);
@@ -927,11 +1281,16 @@

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200707160141.l6G1fcvA092417>