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>