1 /*
2  * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /* $Id: lwsearch.c,v 1.13 2007/06/19 23:46:59 tbox Exp $ */
19 
20 /*! \file */
21 
22 #include <config.h>
23 
24 #include <isc/magic.h>
25 #include <isc/mem.h>
26 #include <isc/mutex.h>
27 #include <isc/result.h>
28 #include <isc/types.h>
29 #include <isc/util.h>
30 
31 #include <dns/name.h>
32 #include <dns/types.h>
33 
34 #include <named/lwsearch.h>
35 #include <named/types.h>
36 
37 #define LWSEARCHLIST_MAGIC		ISC_MAGIC('L', 'W', 'S', 'L')
38 #define VALID_LWSEARCHLIST(l)		ISC_MAGIC_VALID(l, LWSEARCHLIST_MAGIC)
39 
40 isc_result_t
ns_lwsearchlist_create(isc_mem_t * mctx,ns_lwsearchlist_t ** listp)41 ns_lwsearchlist_create(isc_mem_t *mctx, ns_lwsearchlist_t **listp) {
42 	ns_lwsearchlist_t *list;
43 	isc_result_t result;
44 
45 	REQUIRE(mctx != NULL);
46 	REQUIRE(listp != NULL && *listp == NULL);
47 
48 	list = isc_mem_get(mctx, sizeof(ns_lwsearchlist_t));
49 	if (list == NULL)
50 		return (ISC_R_NOMEMORY);
51 
52 	result = isc_mutex_init(&list->lock);
53 	if (result != ISC_R_SUCCESS) {
54 		isc_mem_put(mctx, list, sizeof(ns_lwsearchlist_t));
55 		return (result);
56 	}
57 	list->mctx = NULL;
58 	isc_mem_attach(mctx, &list->mctx);
59 	list->refs = 1;
60 	ISC_LIST_INIT(list->names);
61 	list->magic = LWSEARCHLIST_MAGIC;
62 
63 	*listp = list;
64 	return (ISC_R_SUCCESS);
65 }
66 
67 void
ns_lwsearchlist_attach(ns_lwsearchlist_t * source,ns_lwsearchlist_t ** target)68 ns_lwsearchlist_attach(ns_lwsearchlist_t *source, ns_lwsearchlist_t **target) {
69 	REQUIRE(VALID_LWSEARCHLIST(source));
70 	REQUIRE(target != NULL && *target == NULL);
71 
72 	LOCK(&source->lock);
73 	INSIST(source->refs > 0);
74 	source->refs++;
75 	INSIST(source->refs != 0);
76 	UNLOCK(&source->lock);
77 
78 	*target = source;
79 }
80 
81 void
ns_lwsearchlist_detach(ns_lwsearchlist_t ** listp)82 ns_lwsearchlist_detach(ns_lwsearchlist_t **listp) {
83 	ns_lwsearchlist_t *list;
84 	isc_mem_t *mctx;
85 
86 	REQUIRE(listp != NULL);
87 	list = *listp;
88 	REQUIRE(VALID_LWSEARCHLIST(list));
89 
90 	LOCK(&list->lock);
91 	INSIST(list->refs > 0);
92 	list->refs--;
93 	UNLOCK(&list->lock);
94 
95 	*listp = NULL;
96 	if (list->refs != 0)
97 		return;
98 
99 	mctx = list->mctx;
100 	while (!ISC_LIST_EMPTY(list->names)) {
101 		dns_name_t *name = ISC_LIST_HEAD(list->names);
102 		ISC_LIST_UNLINK(list->names, name, link);
103 		dns_name_free(name, list->mctx);
104 		isc_mem_put(list->mctx, name, sizeof(dns_name_t));
105 	}
106 	list->magic = 0;
107 	isc_mem_put(mctx, list, sizeof(ns_lwsearchlist_t));
108 	isc_mem_detach(&mctx);
109 }
110 
111 isc_result_t
ns_lwsearchlist_append(ns_lwsearchlist_t * list,dns_name_t * name)112 ns_lwsearchlist_append(ns_lwsearchlist_t *list, dns_name_t *name) {
113 	dns_name_t *newname;
114 	isc_result_t result;
115 
116 	REQUIRE(VALID_LWSEARCHLIST(list));
117 	REQUIRE(name != NULL);
118 
119 	newname = isc_mem_get(list->mctx, sizeof(dns_name_t));
120 	if (newname == NULL)
121 		return (ISC_R_NOMEMORY);
122 	dns_name_init(newname, NULL);
123 	result = dns_name_dup(name, list->mctx, newname);
124 	if (result != ISC_R_SUCCESS) {
125 		isc_mem_put(list->mctx, newname, sizeof(dns_name_t));
126 		return (result);
127 	}
128 	ISC_LINK_INIT(newname, link);
129 	ISC_LIST_APPEND(list->names, newname, link);
130 	return (ISC_R_SUCCESS);
131 }
132 
133 void
ns_lwsearchctx_init(ns_lwsearchctx_t * sctx,ns_lwsearchlist_t * list,dns_name_t * name,unsigned int ndots)134 ns_lwsearchctx_init(ns_lwsearchctx_t *sctx, ns_lwsearchlist_t *list,
135 		    dns_name_t *name, unsigned int ndots)
136 {
137 	INSIST(sctx != NULL);
138 	sctx->relname = name;
139 	sctx->searchname = NULL;
140 	sctx->doneexact = ISC_FALSE;
141 	sctx->exactfirst = ISC_FALSE;
142 	sctx->ndots = ndots;
143 	if (dns_name_isabsolute(name) || list == NULL) {
144 		sctx->list = NULL;
145 		return;
146 	}
147 	sctx->list = list;
148 	sctx->searchname = ISC_LIST_HEAD(sctx->list->names);
149 	if (dns_name_countlabels(name) > ndots)
150 		sctx->exactfirst = ISC_TRUE;
151 }
152 
153 void
ns_lwsearchctx_first(ns_lwsearchctx_t * sctx)154 ns_lwsearchctx_first(ns_lwsearchctx_t *sctx) {
155 	REQUIRE(sctx != NULL);
156 	UNUSED(sctx);
157 }
158 
159 isc_result_t
ns_lwsearchctx_next(ns_lwsearchctx_t * sctx)160 ns_lwsearchctx_next(ns_lwsearchctx_t *sctx) {
161 	REQUIRE(sctx != NULL);
162 
163 	if (sctx->list == NULL)
164 		return (ISC_R_NOMORE);
165 
166 	if (sctx->searchname == NULL) {
167 		INSIST (!sctx->exactfirst || sctx->doneexact);
168 		if (sctx->exactfirst || sctx->doneexact)
169 			return (ISC_R_NOMORE);
170 		sctx->doneexact = ISC_TRUE;
171 	} else {
172 		if (sctx->exactfirst && !sctx->doneexact)
173 			sctx->doneexact = ISC_TRUE;
174 		else {
175 			sctx->searchname = ISC_LIST_NEXT(sctx->searchname,
176 							 link);
177 			if (sctx->searchname == NULL && sctx->doneexact)
178 				return (ISC_R_NOMORE);
179 		}
180 	}
181 
182 	return (ISC_R_SUCCESS);
183 }
184 
185 isc_result_t
ns_lwsearchctx_current(ns_lwsearchctx_t * sctx,dns_name_t * absname)186 ns_lwsearchctx_current(ns_lwsearchctx_t *sctx, dns_name_t *absname) {
187 	dns_name_t *tname;
188 	isc_boolean_t useexact = ISC_FALSE;
189 
190 	REQUIRE(sctx != NULL);
191 
192 	if (sctx->list == NULL ||
193 	    sctx->searchname == NULL ||
194 	    (sctx->exactfirst && !sctx->doneexact))
195 		useexact = ISC_TRUE;
196 
197 	if (useexact) {
198 		if (dns_name_isabsolute(sctx->relname))
199 			tname = NULL;
200 		else
201 			tname = dns_rootname;
202 	} else
203 		tname = sctx->searchname;
204 
205 	return (dns_name_concatenate(sctx->relname, tname, absname, NULL));
206 }
207