Merge from vendor branch TCPDUMP:
[dragonfly.git] / contrib / bind-9.3 / lib / dns / forward.c
1 /*
2  * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and 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: forward.c,v 1.5.206.3 2005/03/17 03:58:30 marka Exp $ */
19
20 #include <config.h>
21
22 #include <isc/magic.h>
23 #include <isc/mem.h>
24 #include <isc/rwlock.h>
25 #include <isc/sockaddr.h>
26 #include <isc/util.h>
27
28 #include <dns/forward.h>
29 #include <dns/rbt.h>
30 #include <dns/result.h>
31 #include <dns/types.h>
32
33 struct dns_fwdtable {
34         /* Unlocked. */
35         unsigned int            magic;
36         isc_mem_t               *mctx;
37         isc_rwlock_t            rwlock;
38         /* Locked by lock. */
39         dns_rbt_t               *table;
40 };
41
42 #define FWDTABLEMAGIC           ISC_MAGIC('F', 'w', 'd', 'T')
43 #define VALID_FWDTABLE(ft)      ISC_MAGIC_VALID(ft, FWDTABLEMAGIC)
44
45 static void
46 auto_detach(void *, void *);
47
48 isc_result_t
49 dns_fwdtable_create(isc_mem_t *mctx, dns_fwdtable_t **fwdtablep) {
50         dns_fwdtable_t *fwdtable;
51         isc_result_t result;
52
53         REQUIRE(fwdtablep != NULL && *fwdtablep == NULL);
54
55         fwdtable = isc_mem_get(mctx, sizeof(dns_fwdtable_t));
56         if (fwdtable == NULL)
57                 return (ISC_R_NOMEMORY);
58
59         fwdtable->table = NULL;
60         result = dns_rbt_create(mctx, auto_detach, fwdtable, &fwdtable->table);
61         if (result != ISC_R_SUCCESS)
62                 goto cleanup_fwdtable;
63
64         result = isc_rwlock_init(&fwdtable->rwlock, 0, 0);
65         if (result != ISC_R_SUCCESS) {
66                 UNEXPECTED_ERROR(__FILE__, __LINE__,
67                                  "isc_rwlock_init() failed: %s",
68                                  isc_result_totext(result));
69                 result = ISC_R_UNEXPECTED;
70                 goto cleanup_rbt;
71         }
72
73         fwdtable->mctx = NULL;
74         isc_mem_attach(mctx, &fwdtable->mctx);
75         fwdtable->magic = FWDTABLEMAGIC;
76         *fwdtablep = fwdtable;
77
78         return (ISC_R_SUCCESS);
79
80    cleanup_rbt:
81         dns_rbt_destroy(&fwdtable->table);
82
83    cleanup_fwdtable:
84         isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
85
86         return (result);
87 }
88
89 isc_result_t
90 dns_fwdtable_add(dns_fwdtable_t *fwdtable, dns_name_t *name,
91                  isc_sockaddrlist_t *addrs, dns_fwdpolicy_t fwdpolicy)
92 {
93         isc_result_t result;
94         dns_forwarders_t *forwarders;
95         isc_sockaddr_t *sa, *nsa;
96
97         REQUIRE(VALID_FWDTABLE(fwdtable));
98
99         forwarders = isc_mem_get(fwdtable->mctx, sizeof(dns_forwarders_t));
100         if (forwarders == NULL)
101                 return (ISC_R_NOMEMORY);
102
103         ISC_LIST_INIT(forwarders->addrs);
104         for (sa = ISC_LIST_HEAD(*addrs);
105              sa != NULL;
106              sa = ISC_LIST_NEXT(sa, link))
107         {
108                 nsa = isc_mem_get(fwdtable->mctx, sizeof(isc_sockaddr_t));
109                 if (nsa == NULL) {
110                         result = ISC_R_NOMEMORY;
111                         goto cleanup;
112                 }
113                 *nsa = *sa;
114                 ISC_LINK_INIT(nsa, link);
115                 ISC_LIST_APPEND(forwarders->addrs, nsa, link);
116         }
117         forwarders->fwdpolicy = fwdpolicy;
118
119         RWLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
120         result = dns_rbt_addname(fwdtable->table, name, forwarders);
121         RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_write);
122
123         if (result != ISC_R_SUCCESS)
124                 goto cleanup;
125
126         return (ISC_R_SUCCESS);
127
128  cleanup:
129         while (!ISC_LIST_EMPTY(forwarders->addrs)) {
130                 sa = ISC_LIST_HEAD(forwarders->addrs);
131                 ISC_LIST_UNLINK(forwarders->addrs, sa, link);
132                 isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t));
133         }
134         isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
135         return (result);
136 }
137
138 isc_result_t
139 dns_fwdtable_find(dns_fwdtable_t *fwdtable, dns_name_t *name,
140                   dns_forwarders_t **forwardersp)
141 {
142         return (dns_fwdtable_find2(fwdtable, name, NULL, forwardersp));
143
144
145 isc_result_t
146 dns_fwdtable_find2(dns_fwdtable_t *fwdtable, dns_name_t *name,
147                    dns_name_t *foundname, dns_forwarders_t **forwardersp)
148 {
149         isc_result_t result;
150
151         REQUIRE(VALID_FWDTABLE(fwdtable));
152
153         RWLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
154
155         result = dns_rbt_findname(fwdtable->table, name, 0, foundname,
156                                   (void **)forwardersp);
157         if (result == DNS_R_PARTIALMATCH)
158                 result = ISC_R_SUCCESS;
159
160         RWUNLOCK(&fwdtable->rwlock, isc_rwlocktype_read);
161
162         return (result);
163 }
164
165 void
166 dns_fwdtable_destroy(dns_fwdtable_t **fwdtablep) {
167         dns_fwdtable_t *fwdtable;
168         isc_mem_t *mctx;
169
170         REQUIRE(fwdtablep != NULL && VALID_FWDTABLE(*fwdtablep));
171
172         fwdtable = *fwdtablep;
173
174         dns_rbt_destroy(&fwdtable->table);
175         isc_rwlock_destroy(&fwdtable->rwlock);
176         fwdtable->magic = 0;
177         mctx = fwdtable->mctx;
178         isc_mem_put(mctx, fwdtable, sizeof(dns_fwdtable_t));
179         isc_mem_detach(&mctx);
180
181         *fwdtablep = NULL;
182 }
183
184 /***
185  *** Private
186  ***/
187
188 static void
189 auto_detach(void *data, void *arg) {
190         dns_forwarders_t *forwarders = data;
191         dns_fwdtable_t *fwdtable = arg;
192         isc_sockaddr_t *sa;
193
194         UNUSED(arg);
195
196         while (!ISC_LIST_EMPTY(forwarders->addrs)) {
197                 sa = ISC_LIST_HEAD(forwarders->addrs);
198                 ISC_LIST_UNLINK(forwarders->addrs, sa, link);
199                 isc_mem_put(fwdtable->mctx, sa, sizeof(isc_sockaddr_t));
200         }
201         isc_mem_put(fwdtable->mctx, forwarders, sizeof(dns_forwarders_t));
202 }