Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / dns / dns_rr.c
blob8820af891bf968fdadf51832665c6c8cac041f37
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* dns_rr 3
6 /* SUMMARY
7 /* resource record memory and list management
8 /* SYNOPSIS
9 /* #include <dns.h>
11 /* DNS_RR *dns_rr_create(qname, rname, type, class, ttl, preference,
12 /* data, data_len)
13 /* const char *qname;
14 /* const char *rname;
15 /* unsigned short type;
16 /* unsigned short class;
17 /* unsigned int ttl;
18 /* unsigned preference;
19 /* const char *data;
20 /* size_t data_len;
22 /* void dns_rr_free(list)
23 /* DNS_RR *list;
25 /* DNS_RR *dns_rr_copy(record)
26 /* DNS_RR *record;
28 /* DNS_RR *dns_rr_append(list, record)
29 /* DNS_RR *list;
30 /* DNS_RR *record;
32 /* DNS_RR *dns_rr_sort(list, compar)
33 /* DNS_RR *list
34 /* int (*compar)(DNS_RR *, DNS_RR *);
36 /* int dns_rr_compare_pref(DNS_RR *a, DNS_RR *b)
37 /* DNS_RR *list
38 /* DNS_RR *list
40 /* DNS_RR *dns_rr_shuffle(list)
41 /* DNS_RR *list;
43 /* DNS_RR *dns_rr_remove(list, record)
44 /* DNS_RR *list;
45 /* DNS_RR *record;
46 /* DESCRIPTION
47 /* The routines in this module maintain memory for DNS resource record
48 /* information, and maintain lists of DNS resource records.
50 /* dns_rr_create() creates and initializes one resource record.
51 /* The \fIqname\fR field specifies the query name.
52 /* The \fIrname\fR field specifies the reply name.
53 /* \fIpreference\fR is used for MX records; \fIdata\fR is a null
54 /* pointer or specifies optional resource-specific data;
55 /* \fIdata_len\fR is the amount of resource-specific data.
57 /* dns_rr_free() releases the resource used by of zero or more
58 /* resource records.
60 /* dns_rr_copy() makes a copy of a resource record.
62 /* dns_rr_append() appends a resource record to a (list of) resource
63 /* record(s).
64 /* A null input list is explicitly allowed.
66 /* dns_rr_sort() sorts a list of resource records into ascending
67 /* order according to a user-specified criterion. The result is the
68 /* sorted list.
70 /* dns_rr_compare_pref() is a dns_rr_sort() helper to sort records
71 /* by their MX preference.
73 /* dns_rr_shuffle() randomly permutes a list of resource records.
75 /* dns_rr_remove() removes the specified record from the specified list.
76 /* The updated list is the result value.
77 /* The record MUST be a list member.
78 /* LICENSE
79 /* .ad
80 /* .fi
81 /* The Secure Mailer license must be distributed with this software.
82 /* AUTHOR(S)
83 /* Wietse Venema
84 /* IBM T.J. Watson Research
85 /* P.O. Box 704
86 /* Yorktown Heights, NY 10598, USA
87 /*--*/
89 /* System library. */
91 #include <sys_defs.h>
92 #include <string.h>
93 #include <stdlib.h>
95 /* Utility library. */
97 #include <msg.h>
98 #include <mymalloc.h>
99 #include <myrand.h>
101 /* DNS library. */
103 #include "dns.h"
105 /* dns_rr_create - fill in resource record structure */
107 DNS_RR *dns_rr_create(const char *qname, const char *rname,
108 ushort type, ushort class,
109 unsigned int ttl, unsigned pref,
110 const char *data, size_t data_len)
112 DNS_RR *rr;
114 rr = (DNS_RR *) mymalloc(sizeof(*rr) + data_len - 1);
115 rr->qname = mystrdup(qname);
116 rr->rname = mystrdup(rname);
117 rr->type = type;
118 rr->class = class;
119 rr->ttl = ttl;
120 rr->pref = pref;
121 if (data && data_len > 0)
122 memcpy(rr->data, data, data_len);
123 rr->data_len = data_len;
124 rr->next = 0;
125 return (rr);
128 /* dns_rr_free - destroy resource record structure */
130 void dns_rr_free(DNS_RR *rr)
132 if (rr) {
133 if (rr->next)
134 dns_rr_free(rr->next);
135 myfree(rr->qname);
136 myfree(rr->rname);
137 myfree((char *) rr);
141 /* dns_rr_copy - copy resource record */
143 DNS_RR *dns_rr_copy(DNS_RR *src)
145 ssize_t len = sizeof(*src) + src->data_len - 1;
146 DNS_RR *dst;
149 * Combine struct assignment and data copy in one block copy operation.
151 dst = (DNS_RR *) mymalloc(len);
152 memcpy((char *) dst, (char *) src, len);
153 dst->qname = mystrdup(src->qname);
154 dst->rname = mystrdup(src->rname);
155 dst->next = 0;
156 return (dst);
159 /* dns_rr_append - append resource record to list */
161 DNS_RR *dns_rr_append(DNS_RR *list, DNS_RR *rr)
163 if (list == 0) {
164 list = rr;
165 } else {
166 list->next = dns_rr_append(list->next, rr);
168 return (list);
171 /* dns_rr_compare_pref - compare resource records by preference */
173 int dns_rr_compare_pref(DNS_RR *a, DNS_RR *b)
175 if (a->pref != b->pref)
176 return (a->pref - b->pref);
177 #ifdef HAS_IPV6
178 if (a->type == b->type) /* 200412 */
179 return 0;
180 if (a->type == T_AAAA)
181 return (-1);
182 if (b->type == T_AAAA)
183 return (+1);
184 #endif
185 return 0;
188 /* dns_rr_sort_callback - glue function */
190 static int (*dns_rr_sort_user) (DNS_RR *, DNS_RR *);
192 static int dns_rr_sort_callback(const void *a, const void *b)
194 DNS_RR *aa = *(DNS_RR **) a;
195 DNS_RR *bb = *(DNS_RR **) b;
197 return (dns_rr_sort_user(aa, bb));
200 /* dns_rr_sort - sort resource record list */
202 DNS_RR *dns_rr_sort(DNS_RR *list, int (*compar) (DNS_RR *, DNS_RR *))
204 int (*saved_user) (DNS_RR *, DNS_RR *);
205 DNS_RR **rr_array;
206 DNS_RR *rr;
207 int len;
208 int i;
211 * Save state and initialize.
213 saved_user = dns_rr_sort_user;
214 dns_rr_sort_user = compar;
217 * Build linear array with pointers to each list element.
219 for (len = 0, rr = list; rr != 0; len++, rr = rr->next)
220 /* void */ ;
221 rr_array = (DNS_RR **) mymalloc(len * sizeof(*rr_array));
222 for (len = 0, rr = list; rr != 0; len++, rr = rr->next)
223 rr_array[len] = rr;
226 * Sort by user-specified criterion.
228 qsort((char *) rr_array, len, sizeof(*rr_array), dns_rr_sort_callback);
231 * Fix the links.
233 for (i = 0; i < len - 1; i++)
234 rr_array[i]->next = rr_array[i + 1];
235 rr_array[i]->next = 0;
236 list = rr_array[0];
239 * Cleanup.
241 myfree((char *) rr_array);
242 dns_rr_sort_user = saved_user;
243 return (list);
246 /* dns_rr_shuffle - shuffle resource record list */
248 DNS_RR *dns_rr_shuffle(DNS_RR *list)
250 DNS_RR **rr_array;
251 DNS_RR *rr;
252 int len;
253 int i;
254 int r;
257 * Build linear array with pointers to each list element.
259 for (len = 0, rr = list; rr != 0; len++, rr = rr->next)
260 /* void */ ;
261 rr_array = (DNS_RR **) mymalloc(len * sizeof(*rr_array));
262 for (len = 0, rr = list; rr != 0; len++, rr = rr->next)
263 rr_array[len] = rr;
266 * Shuffle resource records.
268 for (i = 0; i < len; i++) {
269 r = myrand() % len;
270 rr = rr_array[i];
271 rr_array[i] = rr_array[r];
272 rr_array[r] = rr;
276 * Fix the links.
278 for (i = 0; i < len - 1; i++)
279 rr_array[i]->next = rr_array[i + 1];
280 rr_array[i]->next = 0;
281 list = rr_array[0];
284 * Cleanup.
286 myfree((char *) rr_array);
287 return (list);
290 /* dns_rr_remove - remove record from list, return new list */
292 DNS_RR *dns_rr_remove(DNS_RR *list, DNS_RR *record)
294 if (list == 0)
295 msg_panic("dns_rr_remove: record not found");
297 if (list == record) {
298 list = record->next;
299 record->next = 0;
300 dns_rr_free(record);
301 } else {
302 list->next = dns_rr_remove(list->next, record);
304 return (list);