PERFORCE change 127144 for review

Fredrik Lindberg fli at FreeBSD.org
Wed Oct 3 14:11:16 PDT 2007


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

Change 127144 by fli at fli_nexus on 2007/10/03 21:11:03

	- Follow changes to the record subsystem.
	- Make dbr_init() return an int to indicate success/failure.
	- Better failure handling (NULL checks etc)
	- Clean up the header file.
	- Minor fixes and comments. 

Affected files ...

.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/dbrec.c#8 edit
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/dbrec.h#5 edit

Differences ...

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

@@ -33,6 +33,7 @@
 #include "output.h"
 #include "record.h"
 #include "log.h"
+#include "util.h"
 #include "var.h"
 
 static void rec_update(struct dbr_ident *, struct vt_data *, size_t);
@@ -60,20 +61,30 @@
 /*
  * Initialize a database record system
  */
-void
+int
 dbr_init(struct dbr *dbr, void *context)
 {
 	struct md_if *mif = context;
+	int error;
 
 	dbr->dbr_ctx = context;
-	MDNS_INIT_SET(dbr, dbr_magic);
-	hashtbl_init(&dbr->dbr_ident, 8, 512, 3);
+	error = hashtbl_init(&dbr->dbr_ident, 8, 512, 3);
+	if (error != 0)
+		goto dbr_init_fail;
 	TAILQ_INIT(&dbr->dbr_ilist);
 
+	MDNS_INIT_SET(dbr, dbr_magic);
 	var_init(&dbr->dbr_vars, mif->mif_glob->g_evl, dbr);
-	/* We only do the IN class */
-	records_init(&dbr->dbr_recs, mdns_c_in);
-	dprintf(DEBUG_DBR, "Database records initialized");
+	error = records_init(&dbr->dbr_recs);
+	if (error != 0)
+		goto dbr_init_fail2;
+	dprintf(DEBUG_DBR, "Record database initialized");
+	return (0);
+dbr_init_fail2:
+	hashtbl_destroy(&dbr->dbr_ident);
+dbr_init_fail:
+	dprintf(DEBUG_DBR, "Failed to initialize record database");
+	return (-1);
 }
 
 /*
@@ -303,6 +314,7 @@
 {
 	struct dbr_ident *dbi;
 	size_t ilen;
+	int error;
 
 	ilen = strlen(ident);
 
@@ -314,12 +326,12 @@
 
 		dbi->dbi_flags &= flags;
 		dbi->dbi_flags |= flags;
-		goto out;
+		goto dbr_ident_fail;
 	}
 
 	dbi = malloc(sizeof(struct dbr_ident));
 	if (dbi == NULL)
-		goto out;
+		goto dbr_ident_fail;
 	bzero(dbi, sizeof(struct dbr_ident));
 	MTX_INIT(dbi, dbi_mtx, NULL);	
 	dbi->dbi_dbr = dbr;
@@ -330,14 +342,20 @@
 	TAILQ_INIT(&dbi->dbi_res_ptr);
 	MDNS_INIT_SET(dbi, dbi_magic);
 
+	error = hashtbl_add(&dbr->dbr_ident, dbi->dbi_ident, ilen, dbi, 0);
+	if (error != 0) {
+		free(dbi->dbi_ident);
+		free(dbi);
+		goto dbr_ident_fail;
+	}
 	TAILQ_INSERT_TAIL(&dbr->dbr_ilist, dbi, dbi_next);
-	hashtbl_add(&dbr->dbr_ident, dbi->dbi_ident, ilen, dbi, 0);
 
 	dprintf(DEBUG_DBR, "Added record set identifier %s, dbi=%x",
 	    ident, dbi);
 	RW_UNLOCK(dbr, dbr_lock);
 	return (0);
-out:
+dbr_ident_fail:
+	dprintf(DEBUG_DBR, "Failed to add record set identifier %s", ident);
 	RW_UNLOCK(dbr, dbr_lock);
 	return (-1);
 }
@@ -420,7 +438,8 @@
 {
 	struct dbr_ident *dbi;
 	char **ident;
-	int i;
+	void *tmp;
+	int i, j;
 
 	MDNS_INIT_ASSERT(dbr, dbr_magic);
 
@@ -429,15 +448,30 @@
 	RW_RLOCK(dbr, dbr_lock);
 	TAILQ_FOREACH(dbi, &dbr->dbr_ilist, dbi_next) {
 		MDNS_INIT_ASSERT(dbi, dbi_magic);
-		ident = realloc(ident, sizeof(char *) * ++i);
+		tmp = realloc(ident, sizeof(char *) * ++i);
+		if (tmp == NULL) {
+			i--;
+			goto dbr_ident_list_fail;
+		}
+		ident = tmp;
 		ident[i - 1] = strdup(dbi->dbi_ident);
+		if (ident[i - 1] == NULL)
+			goto dbr_ident_list_fail;
 	}
 	RW_UNLOCK(dbr, dbr_lock);
 
-	ident = realloc(ident, sizeof(char *) * ++i);
+	tmp = realloc(ident, sizeof(char *) * ++i);
+	if (tmp == NULL)
+		goto dbr_ident_list_fail;
 	ident[i - 1] = NULL;
 
 	return (ident);
+dbr_ident_list_fail:
+	for (j = 0; j < i; j++)
+		free(ident[j]);
+	if (ident != NULL)
+		free(ident);
+	return (NULL);
 }
 
 /*
@@ -953,7 +987,9 @@
 	struct record *r;
 	size_t i, vtd_len;
 	struct vt_data *vtd;
+	struct recpar rp;
 	char *p;
+	int error;
 
 	dbr = dbi->dbi_dbr;
 	MDNS_INIT_ASSERT(dbr, dbr_magic);
@@ -968,10 +1004,15 @@
 	MDNS_INIT_SET(dr, dr_magic);
 
 	p = mdns_name_encode(nam, wcslen(nam), MDNS_ENC_AUTO);
+	if (p == NULL)
+		goto rec_add_fail;
 	r = &dr->dr_rec;
-	record_get(&dbr->dbr_recs, &r, RECORD_NOALLOC, p);
-	record_setparent(r, dr);
+	rp.rp_handle = dr;
+	rp.rp_del_cb = NULL;
+	error = record_get(&dbr->dbr_recs, &r, &rp, REC_NOALLOC, p);
 	free(p);
+	if (error != 0)
+		goto rec_add_fail;
 
 	TAILQ_INSERT_TAIL(&dbi->dbi_rech, dr, dr_next);
 	dbi->dbi_records++;
@@ -987,10 +1028,8 @@
 			dr2 = TAILQ_FIRST(&dbi2->dbi_rech);
 			dsh = res_add(dr, dir, NULL, dr2->dr_name);
 
-			while ((dr2 = TAILQ_NEXT(dr2, dr_next))
-			    != NULL) {
+			while ((dr2 = TAILQ_NEXT(dr2, dr_next)) != NULL)
 				res_add(dr, dir, dsh, dr2->dr_name);
-			}
 		}
 		else {
 			vtd = var_expand(&dbr->dbr_vars, dir->dir_data.wp,
@@ -1002,8 +1041,12 @@
 			var_vtdfree(vtd, vtd_len);
 		}
 	}
-
+	dprintf(DEBUG_DBR, "Added real record, nam=%ls", nam);
 	return (dr);
+rec_add_fail:
+	free(dr->dr_name);
+	dprintf(DEBUG_DBR, "Failed to add record to database, nam=%ls", nam);
+	return (NULL);
 }
 
 /*
@@ -1050,8 +1093,8 @@
 	struct dbr_res *ds, *ds2;
 	struct dbr_rec *dr;
 	size_t rlen;
-	ssize_t diff;
 	char *p;
+	int error;
 	uint32_t i;
 
 	assert(dsh->ds_chead == dsh);
@@ -1070,16 +1113,65 @@
 
 	if (dsh->ds_data != NULL)
 		free(dsh->ds_data);
-	dsh->ds_data = _wcsdup(res[0]);
-	p = mdns_res_encode(dir->dir_class, dir->dir_type, res[0],
-	    MDNS_ENC_WCHAR, wcslen(res[0]), &rlen);
-	record_res_setdata(&dsh->ds_res, p, rlen);
+
+	/*
+	 * Try each resource, continue for as long as there are resources
+	 * and they keep failing.
+	 */
+	for (i = 0; i < reslen; i++) {
+		p = mdns_res_encode(dir->dir_class, dir->dir_type, res[i],
+		    MDNS_ENC_WCHAR, wcslen(res[i]), &rlen);
+		if (p == NULL)
+			continue;
+		error = record_res_setdata(&dsh->ds_res, REC_RESOWN, p, rlen);
+		if (error != 0) {
+			free(p);
+			continue;
+		}
+		dsh->ds_data = _wcsdup(res[i]);
+		i++;
+		break;
+	}
 
-	i = 1;
 	/*
 	 * Replace resource data as long as there is enough clones
 	 * and results available.
 	 */
+	ds = TAILQ_FIRST(&dsh->ds_clone.head);
+	for (; i < reslen; i++) {
+		if (ds == NULL)
+			break;
+		if (ds->ds_data != NULL)
+			free(ds->ds_data);
+		ds->ds_data = _wcsdup(res[i]);
+
+		p = mdns_res_encode(dir->dir_class, dir->dir_type, res[i],
+		    MDNS_ENC_WCHAR, wcslen(res[i]), &rlen);
+		if (p == NULL)
+			continue;
+		error = record_res_setdata(&ds->ds_res, REC_RESOWN, p, rlen);
+		if (error != 0)
+			continue;
+
+		ds = TAILQ_NEXT(ds, ds_next);
+	}
+
+	if (ds == NULL) {
+		/* More results than clones, expand */
+		for (; i < reslen; i++) {
+			res_add(dr, dir, dsh, res[i]);
+		}
+	}
+	else {
+		/* More clones than results, shrink */
+		while (ds != NULL) {
+			ds2 = TAILQ_NEXT(ds, ds_next);
+			res_del(ds);
+			ds = ds2;
+		}
+	}
+
+#if 0
 	TAILQ_FOREACH(ds, &dsh->ds_clone.head, ds_clone.next) {
 		if (i == dsh->ds_clones || i == reslen)
 			break;
@@ -1089,7 +1181,14 @@
 
 		p = mdns_res_encode(dir->dir_class, dir->dir_type, res[i],
 		    MDNS_ENC_WCHAR, wcslen(res[i]), &rlen);
-		record_res_setdata(&ds->ds_res, p, rlen);
+		if (p == NULL) {
+			dprintf(DEBUG_DBR, "Failed to encode resource");
+			continue;
+		}
+		error = record_res_setdata(&ds->ds_res, REC_RESOWN, p, rlen);
+		if (error != 0) {
+
+		}
 		i++;
 	}
 
@@ -1109,7 +1208,7 @@
 			res_del(ds);
 		}
 	}
-
+#endif
 }
 
 /*
@@ -1200,16 +1299,21 @@
 res_add(struct dbr_rec *dr, struct dbr_ident_res *dir, struct dbr_res *dsh,
     wchar_t *res)
 {
+	struct dbr *dbr;
 	struct dbr_res *ds;
 	struct dbr_ident *dbi;
-	char *p;
-	size_t rlen;
 	struct record *r;
 	struct record_res *rr;
+	struct recpar rp;
+	size_t rlen;
+	int error;
+	char *p;
 
 	MDNS_INIT_ASSERT(dir, dir_magic);
 	dbi = dir->dir_dbi;
 	MDNS_INIT_ASSERT(dbi, dbi_magic);
+	dbr = dbi->dbi_dbr;
+	MDNS_INIT_ASSERT(dbr, dbr_magic);
 
 	ds = malloc(sizeof(struct dbr_res));
 	if (ds == NULL)
@@ -1233,21 +1337,38 @@
 	r = &dr->dr_rec;
 	rr = &ds->ds_res;
 
+	ds->ds_data = _wcsdup(res);
+	if (ds->ds_data == NULL)
+		goto res_add_fail;
+
 	p = mdns_res_encode(dir->dir_class, dir->dir_type, res,
 	    MDNS_ENC_WCHAR, wcslen(res), &rlen);
+	if (p == NULL)
+		goto res_add_fail2;
 
-	record_res_add(r, &rr, RECORD_NOALLOC, dir->dir_type, p, rlen);
-	record_res_setparent(&ds->ds_res, ds);
-
+	rp.rp_handle = ds;
+	rp.rp_del_cb = NULL;
+	error = record_res_add(&dbr->dbr_recs, &rr,
+	    REC_NOALLOC | REC_OBJNAME | REC_RESOWN,
+	    &rp, r, dir->dir_class, dir->dir_type, p, rlen);
+	if (error != 0) {
+		free(p);
+		goto res_add_fail2;
+	}
+	
 	ds->ds_rec = dr;
-	ds->ds_data = _wcsdup(res);
 	ds->ds_dir = dir;
 	MDNS_INIT_SET(ds, ds_magic);
 
 	dprintf(DEBUG_DBR, "Added real resource ds=%x to record %ls, dr=%x, "
 	    "dir=%x", ds, dr->dr_name, dr, dir);
-
 	return (ds);
+res_add_fail2:
+	free(ds->ds_data);
+res_add_fail:
+	dprintf(DEBUG_DBR, "Failed to add real resource %ls, dir=%p",
+	    res, dir);
+	return (NULL);
 }
 
 /*
@@ -1285,87 +1406,93 @@
 	free(ds);
 }
 
-#if 0
 /*
- * Remove a resource from a database record
- *   ds - Database resource pointer
- *
- * All clones will be removed aswell, to remove/free only one resource
- * use res_del().
+ * Look up exact matching resource
  */
-void
-dbr_res_del(struct dbr_res *ds)
+struct dbr_res *
+dbr_find_res(struct dbr *dbr, char *name, uint16_t class, uint16_t type,
+    char *res, size_t rlen)
 {
-	struct dbr_rec *dr;
-	struct dbr *dbr;
-	struct dbr_type *dt;
-	struct dbr_res *ds2, *ds_tmp;
+	struct record_res *rr;
 
-	MDNS_INIT_ASSERT(ds, ds_magic);
-	dt = ds->ds_type;
-	MDNS_INIT_ASSERT(dt, dt_magic);
-	dr = dt->dt_rec;
-	MDNS_INIT_ASSERT(dr, dr_magic);
-	dbr = dr->dr_dbr;
-	MDNS_INIT_ASSERT(dbr, dbr_magic);
+	/* Unlocked by either dbr_find_next() or dbr_find_end() */
+	RW_RLOCK(dbr, dbr_lock);
 
-	ds2 = ds->ds_chead;
-	if (ds2->ds_flags & DS_POINTER)
-		TAILQ_REMOVE(&ds2->ds_vdata.rec->dr_res_ptr, ds2, ds_ptr_next);
-	else
-		var_dereg(&dbr->dbr_vars, ds2->ds_vdata.wp, ds2);
-
-	TAILQ_FOREACH_SAFE(ds, &ds2->ds_clone.head, ds_clone.next, ds_tmp) {
-		dprintf(DEBUG_DBR, "Removing clone %x (orig %x)", ds, ds2);
-		res_del(ds);
-	}
-
-	res_del(ds2);
-	record_type_release(&dt->dt_type);
-	dprintf(DEBUG_DBR, "Database resource %x removed", ds2);
+	rr = record_res_find(&dbr->dbr_recs, 0, name, class, type, res, rlen);
+	if (rr == NULL)
+		goto dbr_find_res_fail;
+	return (record_res_getparent(rr));
+dbr_find_res_fail:
+	RW_UNLOCK(dbr, dbr_lock);
+	return (NULL);
 }
-#endif
 
 struct dbr_res *
-dbr_find_res(struct dbr *dbr, char *name, uint16_t type, char *res,
-    size_t rlen)
+dbr_find(struct dbr *dbr, const char *name, uint16_t class, uint16_t type)
 {
+	struct record_res *rr;
 	struct record_type *rt;
-	struct record_res *rr;
+
+	/* Unlocked by either dbr_find_next() or dbr_find_end() */
+	RW_RLOCK(dbr, dbr_lock);
+
+	rt = record_type_find(&dbr->dbr_recs, REC_CTANY, name, class, type);
+	if (rt == NULL)
+		goto dbr_find_fail;
 
-	rt = record_type_find(&dbr->dbr_recs, name, type);
-	record_type_foreach(rr, rt) {
-		if (rlen == rr->rr_len)
-			if (memcmp(res, rr->rr_data, rlen) == 0)
-				return (record_res_getparent(rr));
-	}
+	rr = record_res_first(rt);
+	if (rr == NULL)
+		goto dbr_find_fail;
+	return (record_res_getparent(rr));
+dbr_find_fail:
+	RW_UNLOCK(dbr, dbr_lock);
 	return (NULL);
 }
 
-struct dbr_type *
-dbr_find_type(struct dbr *dbr, char *name, uint16_t type)
+struct dbr_res *
+dbr_find_next(struct dbr *dbr, struct dbr_res *ds, uint16_t class,
+    uint16_t type)
 {
+	struct record_res *rr;
 	struct record_type *rt;
-	struct dbr_type *dt = NULL;
+	struct record_class *rc;
+
+	rr = &ds->ds_res;
+	rt = record_get_type(rr);
+	rc = record_get_class(rt);
+	rr = record_res_next(rr);
+	if (rr != NULL)
+		return (record_res_getparent(rr));
 
-	rt = record_type_find(&dbr->dbr_recs, name, type);
-	if (rt != NULL)
-		dt = record_type_getparent(rt);
+	rt = record_type_find_next(rt, type);
+	if (rt != NULL) {
+		rr = record_res_first(rt);
+		if (rr == NULL)
+			goto dbr_find_next_end;
+		return (record_res_getparent(rr));
+	}
 
-	return (dt);
+	rc = record_class_find_next(rc, class);
+	if (rc == NULL)
+		goto dbr_find_next_end;
+	rt = record_type_find(&dbr->dbr_recs, REC_CTANY | REC_OBJCLASS, NULL,
+	    (uintptr_t)rc, type);
+	if (rt == NULL)
+		goto dbr_find_next_end;
+	rr = record_res_first(rt);
+	if (rr == NULL)
+		goto dbr_find_next_end;
+	return (record_res_getparent(rr));
+dbr_find_next_end:
+	RW_UNLOCK(dbr, dbr_lock);
+	return (NULL);
 }
 
-struct dbr_rec *
-dbr_find(struct dbr *dbr, char *name)
+void
+dbr_find_end(struct dbr *dbr)
 {
-	struct record *r;
-	struct dbr_rec *dr = NULL;
 
-	r = record_find(&dbr->dbr_recs, name);
-	if (r != NULL)
-		dr = record_getparent(r);
-
-	return (dr);
+	RW_UNLOCK(dbr, dbr_lock);
 }
 
 /*
@@ -1508,6 +1635,7 @@
 dbr_tiebreak(struct dbr *dbr __unused, struct dbr_rec *dr, struct record *pr)
 {
 	struct record *r;
+	struct record_class *rc, *prc;
 	struct record_type *rt, *prt;
 	struct record_res *rr, *prr;
 	int diff, len;
@@ -1519,68 +1647,92 @@
 	if (!(dr->dr_flags & DR_PROBING))
 		return;
 
-	prt = record_first(pr);
+	prc = record_class_first(pr);
+	if (prc == NULL)
+		return;
+
 	if (prt == NULL)
 		return;
 
 	r = &dr->dr_rec;
-	rt = record_first(r);
+	rc = record_class_first(r);
 
 	/*
-	 * Compare record types one by one, the numerical greater one
-	 * wins. If types are equal, its resource data is byte compared.
+	 * Compare resources pairwaise, numerical greater one wins.
+	 * The record sub-system keeps classes and types sorted.
 	 */
-	while (rt != NULL && prt != NULL) {
-		if (prt->rt_type > rt->rt_type) {
+	while (rc != NULL && prc != NULL) {
+		if (prc->rc_class > rc->rc_class) {
 			outcome = 1;
 			break;
 		}
-		else if (prt->rt_type < rt->rt_type) {
+		else if (prc->rc_class < rc->rc_class) {
 			outcome = 2;
 			break;
 		}
+	
+		prt = record_type_first(prc);
+		rt = record_type_first(rc);
+
+		while (rt != NULL && prt != NULL) {
+			if (prt->rt_type > rt->rt_type) {
+				outcome = 1;
+				break;
+			}
+			else if (prt->rt_type < rt->rt_type) {
+				outcome = 2;
+				break;
+			}
 
-		rr = record_type_first(rt);
-		prr = record_type_first(prt);
+			rr = record_res_first(rt);
+			prr = record_res_first(prt);
 
-		while (rr != NULL && prr != NULL) {
-			len = rr->rr_len > prr->rr_len ?
-			    prr->rr_len : rr->rr_len;
+			while (rr != NULL && prr != NULL) {
+				len = rr->rr_len > prr->rr_len ?
+				    prr->rr_len : rr->rr_len;
 
-			diff = memcmp(rr->rr_data, prr->rr_data, len);
-			if (diff < 0)
-				outcome = 1;	
-			else if (diff > 0)
-				outcome = 2;
-			/*
-			 * If the data differs in length and the data upto
-			 * the common minimum length is identical we
-			 * assume that the longest resource is the
-			 * "lexiographically later" one.
-			 */
-			else if (diff == 0) {
-				if (prr->rr_len > rr->rr_len)
-					outcome = 1;
-				else if (rr->rr_len > prr->rr_len)
+				diff = memcmp(rr->rr_data, prr->rr_data, len);
+				if (diff < 0)
+					outcome = 1;	
+				else if (diff > 0)
 					outcome = 2;
+				/*
+			 	 * If the data differs in length and the data
+				 * upto the common minimum length is identical
+				 * we assume that the longest resource is the
+			 	 * "lexiographically later" one.
+			 	 */
+				else if (diff == 0) {
+					if (prr->rr_len > rr->rr_len)
+						outcome = 1;
+					else if (rr->rr_len > prr->rr_len)
+						outcome = 2;
+				}
 			}
+			if (prr != NULL && rr == NULL)
+				outcome = 1;
+			else if (prr == NULL && rr != NULL)
+				outcome = 2;
+
+			if (outcome != 0)
+				break;
+
+			rt = record_type_next(rt);
+			prt = record_type_next(prt);
 		}
-		if (prr != NULL && rr == NULL)
-			outcome = 1;
-		else if (prr == NULL && rr != NULL)
-			outcome = 2;
-
 		if (outcome != 0)
 			break;
-
-		rt = record_next(rt);
-		prt = record_next(prt);
 	}
 
 	/*
 	 * If the peer still has record types, but we don't we are
 	 * deemed the loser and the other way around.
 	 */
+	if (prc != NULL && rc == NULL)
+		outcome = 1;
+	else if (prc == NULL && rc != NULL)
+		outcome = 2;
+
 	if (prt != NULL && rt == NULL)
 		outcome = 1;
 	else if (prt == NULL && rt != NULL)
@@ -1594,7 +1746,7 @@
 		dprintf(DEBUG_DBR, "Lost tie-breaking on %ls", dr->dr_name);
 		col_probe(dr);
 	}
-	else if (outcome == 1) {
+	else if (outcome == 2) {
 		dprintf(DEBUG_DBR, "Won tie-breaking on %ls", dr->dr_name);
 	}
 }
@@ -1610,6 +1762,7 @@
 	struct mdns_rrset *rs;
 	struct dbr_res *ds;
 	struct record *r;
+	struct record_class *rc;
 	struct record_type *rt;
 	struct record_res *rr;
 	struct mdns_pkgchain pc;
@@ -1633,8 +1786,8 @@
 	}
 
 	/* Check if resource data is identical with what we have */
-	ds = dbr_find_res(dbr, prs->r_name, prs->r_type, prs->r_data,
-	    prs->r_datalen);
+	ds = dbr_find_res(dbr, prs->r_name, prs->r_class, prs->r_type,
+	    prs->r_data, prs->r_datalen);
 	if (ds != NULL) {
 		dprintf(DEBUG_DBR, "Identical resource data on record %s, "
 		    "no need to defend", prs->r_name);
@@ -1645,16 +1798,18 @@
 	mdns_pkgchain_init(&mif->mif_stack, &pc, MDNS_PC_NONE);
 
 	r = &dr->dr_rec;
-	record_foreach(rt, r) {
-		record_type_foreach(rr, rt) {
-			rs = mdns_pkg_getrrset();
-			mdns_rrset_name(rs, r->r_name);
-			rs->r_type = rt->rt_type;
-			rs->r_class = mdns_c_in;
-			rs->r_cflush = 1;
-			rs->r_datalen = rr->rr_len;
-			rs->r_data = rr->rr_data;
-			mdns_pkg_addanswer(&pc, rs, 0);
+	record_foreach(rc, r) {
+		record_class_foreach(rt, rc) {
+			record_type_foreach(rr, rt) {
+				rs = mdns_pkg_getrrset();
+				mdns_rrset_name(rs, r->r_name);
+				rs->r_type = rt->rt_type;
+				rs->r_class = rc->rc_class;
+				rs->r_cflush = 1;
+				rs->r_datalen = rr->rr_len;
+				rs->r_data = rr->rr_data;
+				mdns_pkg_addanswer(&pc, rs, 0);
+			}
 		}
 	}
 	oq_enqueue(&mif->mif_oq, &pc, family, NULL, 0);
@@ -1662,23 +1817,6 @@
 	RW_UNLOCK(dbr, dbr_lock);
 }
 
-static void
-record_probe_cb(struct record *r, void *arg)
-{
-	struct dbr_pac *pac;
-	struct dbr_rec *dr;
-
-	pac = arg;
-	MDNS_INIT_ASSERT(pac, pac_magic);
-	dr = record_getparent(r);
-	if (dr->dr_flags & DR_PROBING)
-		dbr_probe_del(dr);
-	if (dr->dr_flags & DR_ANNOUNCE)
-		dbr_an_del(dr);
-	if (!(dr->dr_flags & DR_SHARED))
-		dbr_probe_add(pac, dr);
-}
-
 /*
  * Initiate probe for all non-shared records in the given database
  *   dbr - Record database
@@ -1687,9 +1825,21 @@
 dbr_probe_all(struct dbr *dbr)
 {
 	struct dbr_pac *pac;
+	struct dbr_rec *dr;
+	struct record *r;
 
+	RW_RLOCK(dbr, dbr_lock);
 	pac = dbr_pac_new(dbr, PAC_PROBE);
-	records_foreach(&dbr->dbr_recs, record_probe_cb, pac);
+	records_foreach(r, &dbr->dbr_recs) {
+		dr = record_getparent(r);
+		if (dr->dr_flags & DR_PROBING)
+			dbr_probe_del(dr);
+		if (dr->dr_flags & DR_ANNOUNCE)
+			dbr_an_del(dr);
+		if (!(dr->dr_flags & DR_SHARED))
+			dbr_probe_add(pac, dr);
+	}
+	RW_UNLOCK(dbr, dbr_lock);
 	dbr_probe_start(pac);
 }
 
@@ -1880,40 +2030,40 @@
 	dbr_pac_start(pac, PAC_PROBE, delay_time, probe_step);
 }
 
-/*
- * Helper function to probe_step(), adds the given record to the
- * specified packet chain.
- */
-static inline void
-probe_add_rec(struct mdns_pkgchain *pc, struct dbr_rec *dr, int step)
+/* Create probe packet to a specific class */
+static inline int
+probe_add_rec_class(struct mdns_pkgchain *pc, struct record_class *rc, int step)
 {
-	struct mdns_qset *qs;
-	struct mdns_rrset *rs;
 	struct record *r;
 	struct record_type *rt;
 	struct record_res *rr;
+	struct mdns_qset *qs;
+	struct mdns_rrset *rs;
 	struct dbr_res *ds;
 	struct dbr_ident_res *dir;
 	struct mdns_rrset rstmp;
-	int error;
+	int error, retval;
 
-	MDNS_INIT_ASSERT(dr, dr_magic);
-	r = &dr->dr_rec;
-
+	r = record_get_record(rc);
 	qs = mdns_pkg_getqset();
+	if (qs == NULL)
+		return (-1);
 	mdns_qset_name(qs, r->r_name);
-	qs->q_class = mdns_c_in;
-	qs->q_type = mdns_in_any;
+	qs->q_class = rc->rc_class;
+	qs->q_type = mdns_t_any;
 	/* unicast on the first 2 steps only */
 	qs->q_unicast = (step < 2) ? 1 : 0;
 
-redo:
 	mdns_pkg_addquestion(pc, qs, 0);
-	record_foreach(rt, r) {
+	record_class_foreach(rt, rc) {
 		record_type_foreach(rr, rt) {
 			ds = record_res_getparent(rr);
 			dir = ds->ds_dir;
 			rs = mdns_pkg_getrrset();
+			if (rs == NULL) {
+				retval = -1;
+				goto probe_add_rec_class_fail;
+			}
 			mdns_rrset_name(rs, r->r_name);
 			rs->r_class = dir->dir_class;
 			rs->r_type = dir->dir_type;
@@ -1922,33 +2072,55 @@
 			rs->r_datalen = rr->rr_len;
 			rs->r_data = rr->rr_data;
 			error = mdns_pkg_addauth(pc, rs, MDNS_PKG_NOAE);
-			if (error == 0)
-				continue;
-			/*
-			 * Out of space in packet.
-			 * Undo everything and re-start with a fresh packet.
-			 */
-			mdns_pkg_delquestion(pc, qs);
-			record_foreach(rt, r) {
-				record_type_foreach(rr, rt) {
-					ds = record_res_getparent(rr);
-					dir = ds->ds_dir;
-					mdns_rrset_name(&rstmp, r->r_name);
-					rstmp.r_class = dir->dir_class;
-					rstmp.r_type = dir->dir_type;
-					rstmp.r_ttl = dir->dir_ttl;
-					rstmp.r_cflush = 0;
-					rstmp.r_datalen = rr->rr_len;
-					rstmp.r_data = rr->rr_data;
-					rs = mdns_pkg_delauth(pc, &rstmp);
-					if (rs != NULL)
-						mdns_pkg_freeset(rs);
-				}
+			if (error != 0) {
+				retval = 1;
+				goto probe_add_rec_class_fail;
 			}
+		}
+	}
+	return (0);
+probe_add_rec_class_fail:
+	mdns_pkg_delquestion(pc, qs);
+	record_class_foreach(rt, rc) {
+		record_type_foreach(rr, rt) {
+			ds = record_res_getparent(rr);
+			dir = ds->ds_dir;
+			mdns_rrset_name(&rstmp, r->r_name);
+			rstmp.r_class = dir->dir_class;
+			rstmp.r_type = dir->dir_type;
+			rstmp.r_ttl = dir->dir_ttl;
+			rstmp.r_cflush = 0;
+			rstmp.r_datalen = rr->rr_len;
+			rstmp.r_data = rr->rr_data;
+			rs = mdns_pkg_delauth(pc, &rstmp);
+			if (rs != NULL)
+				mdns_pkg_freeset(rs);
+		}
+	}
+	return (1);
+}
 
+/*
+ * Helper function to probe_step(), adds the given record to the
+ * specified packet chain.
+ */
+static inline void
+probe_add_rec(struct mdns_pkgchain *pc, struct dbr_rec *dr, int step)
+{
+	struct record *r;
+	struct record_class *rc;
+	int error;
+
+	MDNS_INIT_ASSERT(dr, dr_magic);
+	r = &dr->dr_rec;
+
+	record_foreach(rc, r) {
+		error = probe_add_rec_class(pc, rc, step);
+		/* Out of space, re-try */
+		if (error > 0) {
 			mdns_pkgchain_expand(pc);
 			mdns_pkg_sethdr(pc, 0, MDNS_HEAD_RESP | MDNS_HEAD_AA);
-			goto redo;
+			probe_add_rec_class(pc, rc, step);
 		}
 	}
 }
@@ -2019,6 +2191,7 @@
 		count++;
 	}
 
+	/* FIXME Must read-lock dbr or keep each ds locked while on queue */
 	if (count) {
 		oq_enqueue(&mif->mif_oq, &pc, AF_INET, NULL, 0);
 #ifdef INET6
@@ -2124,10 +2297,14 @@
 	 */
 	TAILQ_FOREACH_SAFE(dr, &pac->pac_head, dr_pac_next, dr2) {
 		MDNS_INIT_ASSERT(dr, dr_magic);
+		r = &dr->dr_rec;
 		TAILQ_FOREACH(ds, &dr->dr_resh, ds_next) {
+			MDNS_INIT_ASSERT(ds, ds_magic);
 			dir = ds->ds_dir;
-			MDNS_INIT_ASSERT(ds, ds_magic);
 			rs = mdns_pkg_getrrset();
+			if (rs == NULL)
+				break;
+			rr = &ds->ds_res;
 			mdns_rrset_name(rs, r->r_name);
 			rs->r_class = dir->dir_class;
 			rs->r_type = dir->dir_type;

==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/dbrec.h#5 (text+ko) ====

@@ -42,11 +42,11 @@
 	MAGIC(dbr_magic);
 	DEF_MTX(dbr_mtx);
 	DEF_RW(dbr_lock);
-	void *dbr_ctx; /* context specific back-pointer */
-	struct records dbr_recs; /* record subsystem */
-	struct vars dbr_vars; /* variable subsystem */
-	struct hashtbl dbr_ident;
-	TAILQ_HEAD(, dbr_ident) dbr_ilist;
+	void		*dbr_ctx;	/* Context specific back-pointer */
+	struct records	dbr_recs;	/* Record subsystem */
+	struct vars	dbr_vars;	/* Variable subsystem */
+	struct hashtbl	dbr_ident;	/* Identifier lookup */
+	TAILQ_HEAD(, dbr_ident) dbr_ilist; /* Identifier list */
 };
 
 /*
@@ -59,7 +59,7 @@
 	MAGIC(dbi_magic);
 	DEF_MTX(dbi_mtx);
 	TAILQ_ENTRY(dbr_ident) dbi_next;
-	struct dbr	*dbi_dbr;	/* back-pointer */
+	struct dbr	*dbi_dbr;	/* Back pointer */
 	char		*dbi_ident;	/* Unique identifier string */
 	wchar_t		**dbi_names;	/* Array of alternative record names */
 	int		dbi_curnam;	/* Current name in use */
@@ -177,50 +177,67 @@
 struct dbr_pac {
 	MAGIC(pac_magic);
 	DEF_MTX(pac_mtx);
-	struct dbr *pac_dbr;
-	int pac_step; /* step counter */
-	int pac_tmr; /* timer id of next step */
-	int pac_flags;
+	struct dbr 	*pac_dbr;
+	int		pac_step; /* step counter */
+	int 		pac_tmr; /* timer id of next step */
+	int 		pac_flags;
 #define PAC_RUNNING	0x01
-#define PAC_PROBE	0x02
-#define PAC_ANNOUNCE		0x04
+#define PAC_PROBE	0x02	/* This is a probe context */
+#define PAC_ANNOUNCE	0x04	/* This is an announce context */
 	TAILQ_HEAD(, dbr_rec) pac_head;
 };
 
-void dbr_init(struct dbr *, void *);
-void dbr_destroy(struct dbr *);
-struct dbr_rec * dbr_add(struct dbr *, char *, wchar_t **, int);
-void dbr_del(struct dbr_rec *);
-struct dbr_rec * dbr_find(struct dbr *, char *);
-struct dbr_type * dbr_find_type(struct dbr *, char *, uint16_t);
-struct dbr_res * dbr_find_res(struct dbr *, char *, uint16_t, char *, size_t);
+/* Initialize record database */
+int	dbr_init(struct dbr *, void *);
+void	dbr_destroy(struct dbr *);
+
+/* Create/remove a record resource identifier */
+int	dbr_ident_add(struct dbr *, char *, int);
+int	dbr_ident_del(struct dbr *, char *);
+
+/* Create/remove a name on an identifier */
+int	dbr_name_add(struct dbr *, char *, wchar_t *);
+int	dbr_name_del(struct dbr *, char *, wchar_t *);
+

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


More information about the p4-projects mailing list