PERFORCE change 123574 for review
Fredrik Lindberg
fli at FreeBSD.org
Mon Jul 16 01:41:39 UTC 2007
http://perforce.freebsd.org/chv.cgi?CH=123574
Change 123574 by fli at 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) <<<
More information about the p4-projects
mailing list