~tritone-team/tritone/eucalyptus

« back to all changes in this revision

Viewing changes to clc/modules/dns/src/main/java/com/eucalyptus/dns/Cache.java

  • Committer: Bazaar Package Importer
  • Author(s): Dustin Kirkland
  • Date: 2009-12-01 21:09:28 UTC
  • mto: This revision was merged to the branch mainline in revision 75.
  • Revision ID: james.westby@ubuntu.com-20091201210928-o2dvg0ubljhb0ft6
Tags: upstream-1.6.1~bzr1083
ImportĀ upstreamĀ versionĀ 1.6.1~bzr1083

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*******************************************************************************
2
 
*Copyright (c) 2009  Eucalyptus Systems, Inc.
3
 
4
 
*  This program is free software: you can redistribute it and/or modify
5
 
*  it under the terms of the GNU General Public License as published by
6
 
*  the Free Software Foundation, only version 3 of the License.
7
 
8
 
9
 
*  This file is distributed in the hope that it will be useful, but WITHOUT
10
 
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 
*  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 
*  for more details.
13
 
14
 
*  You should have received a copy of the GNU General Public License along
15
 
*  with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
 
*  Please contact Eucalyptus Systems, Inc., 130 Castilian
18
 
*  Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
19
 
*  if you need additional information or have any questions.
20
 
21
 
*  This file may incorporate work covered under the following copyright and
22
 
*  permission notice:
23
 
24
 
*    Software License Agreement (BSD License)
25
 
26
 
*    Copyright (c) 2008, Regents of the University of California
27
 
*    All rights reserved.
28
 
29
 
*    Redistribution and use of this software in source and binary forms, with
30
 
*    or without modification, are permitted provided that the following
31
 
*    conditions are met:
32
 
33
 
*      Redistributions of source code must retain the above copyright notice,
34
 
*      this list of conditions and the following disclaimer.
35
 
36
 
*      Redistributions in binary form must reproduce the above copyright
37
 
*      notice, this list of conditions and the following disclaimer in the
38
 
*      documentation and/or other materials provided with the distribution.
39
 
40
 
*    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
41
 
*    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
42
 
*    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
43
 
*    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
44
 
*    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45
 
*    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46
 
*    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
47
 
*    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
48
 
*    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49
 
*    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50
 
*    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
51
 
*    THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
52
 
*    LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
53
 
*    SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
54
 
*    IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
55
 
*    BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
56
 
*    THE REGENTSā€™ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
57
 
*    OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
58
 
*    WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
59
 
*    ANY SUCH LICENSES OR RIGHTS.
60
 
*******************************************************************************/
 
2
 *Copyright (c) 2009  Eucalyptus Systems, Inc.
 
3
 * 
 
4
 *  This program is free software: you can redistribute it and/or modify
 
5
 *  it under the terms of the GNU General Public License as published by
 
6
 *  the Free Software Foundation, only version 3 of the License.
 
7
 * 
 
8
 * 
 
9
 *  This file is distributed in the hope that it will be useful, but WITHOUT
 
10
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
11
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
12
 *  for more details.
 
13
 * 
 
14
 *  You should have received a copy of the GNU General Public License along
 
15
 *  with this program.  If not, see <http://www.gnu.org/licenses/>.
 
16
 * 
 
17
 *  Please contact Eucalyptus Systems, Inc., 130 Castilian
 
18
 *  Dr., Goleta, CA 93101 USA or visit <http://www.eucalyptus.com/licenses/>
 
19
 *  if you need additional information or have any questions.
 
20
 * 
 
21
 *  This file may incorporate work covered under the following copyright and
 
22
 *  permission notice:
 
23
 * 
 
24
 *    Software License Agreement (BSD License)
 
25
 * 
 
26
 *    Copyright (c) 2008, Regents of the University of California
 
27
 *    All rights reserved.
 
28
 * 
 
29
 *    Redistribution and use of this software in source and binary forms, with
 
30
 *    or without modification, are permitted provided that the following
 
31
 *    conditions are met:
 
32
 * 
 
33
 *      Redistributions of source code must retain the above copyright notice,
 
34
 *      this list of conditions and the following disclaimer.
 
35
 * 
 
36
 *      Redistributions in binary form must reproduce the above copyright
 
37
 *      notice, this list of conditions and the following disclaimer in the
 
38
 *      documentation and/or other materials provided with the distribution.
 
39
 * 
 
40
 *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
41
 *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 
42
 *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 
43
 *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 
44
 *    OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
45
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
46
 *    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
47
 *    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 
48
 *    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
49
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
50
 *    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. USERS OF
 
51
 *    THIS SOFTWARE ACKNOWLEDGE THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE
 
52
 *    LICENSED MATERIAL, COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS
 
53
 *    SOFTWARE, AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
 
54
 *    IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, SANTA
 
55
 *    BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, WHICH IN
 
56
 *    THE REGENTSā€™ DISCRETION MAY INCLUDE, WITHOUT LIMITATION, REPLACEMENT
 
57
 *    OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO IDENTIFIED, OR
 
58
 *    WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT NEEDED TO COMPLY WITH
 
59
 *    ANY SUCH LICENSES OR RIGHTS.
 
60
 *******************************************************************************/
61
61
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
62
62
 
63
63
package com.eucalyptus.dns;
96
96
 
97
97
public class Cache {
98
98
 
99
 
private interface Element {
100
 
        public boolean expired();
101
 
        public int compareCredibility(int cred);
102
 
        public int getType();
103
 
}
104
 
 
105
 
private static int
106
 
limitExpire(long ttl, long maxttl) {
107
 
        if (maxttl >= 0 && maxttl < ttl)
108
 
                ttl = maxttl;
109
 
        int expire = (int)((System.currentTimeMillis() / 1000) + ttl);
110
 
        if (expire < 0 || expire > Integer.MAX_VALUE)
111
 
                return Integer.MAX_VALUE;
112
 
        return expire;
113
 
}
114
 
 
115
 
private static class CacheRRset extends RRset implements Element {
116
 
        int credibility;
117
 
        int expire;
118
 
 
119
 
        public
120
 
        CacheRRset(Record rec, int cred, long maxttl) {
121
 
                super();
122
 
                this.credibility = cred;
123
 
                this.expire = limitExpire(rec.getTTL(), maxttl);
124
 
                addRR(rec);
125
 
        }
126
 
 
127
 
        public
128
 
        CacheRRset(RRset rrset, int cred, long maxttl) {
129
 
                super(rrset);
130
 
                this.credibility = cred;
131
 
                this.expire = limitExpire(rrset.getTTL(), maxttl);
132
 
        }
133
 
 
134
 
        public final boolean
135
 
        expired() {
136
 
                int now = (int)(System.currentTimeMillis() / 1000);
137
 
                return (now >= expire);
138
 
        }
139
 
 
140
 
        public final int
141
 
        compareCredibility(int cred) {
142
 
                return credibility - cred;
143
 
        }
144
 
 
145
 
        public String
146
 
        toString() {
147
 
                StringBuffer sb = new StringBuffer();
148
 
                sb.append(super.toString());
149
 
                sb.append(" cl = ");
150
 
                sb.append(credibility);
151
 
                return sb.toString();
152
 
        }
153
 
}
154
 
 
155
 
private static class NegativeElement implements Element {
156
 
        int type;
157
 
        Name name;
158
 
        SOARecord soa;
159
 
        int credibility;
160
 
        int expire;
161
 
 
162
 
        public
163
 
        NegativeElement(Name name, int type, SOARecord soa, int cred,
164
 
                        long maxttl)
165
 
        {
166
 
                this.name = name;
167
 
                this.type = type;
168
 
                this.soa = soa;
169
 
                long cttl = 0;
170
 
                if (soa != null)
171
 
                        cttl = soa.getMinimum();
172
 
                this.credibility = cred;
173
 
                this.expire = limitExpire(cttl, maxttl);
174
 
        }
175
 
 
176
 
        public int
177
 
        getType() {
178
 
                return type;
179
 
        }
180
 
 
181
 
        public final boolean
182
 
        expired() {
183
 
                int now = (int)(System.currentTimeMillis() / 1000);
184
 
                return (now >= expire);
185
 
        }
186
 
 
187
 
        public final int
188
 
        compareCredibility(int cred) {
189
 
                return credibility - cred;
190
 
        }
191
 
 
192
 
        public String
193
 
        toString() {
194
 
                StringBuffer sb = new StringBuffer();
195
 
                if (type == 0)
196
 
                        sb.append("NXDOMAIN " + name);
197
 
                else
198
 
                        sb.append("NXRRSET " + name + " " + Type.string(type));
199
 
                sb.append(" cl = ");
200
 
                sb.append(credibility);
201
 
                return sb.toString();
202
 
        }
203
 
}
204
 
 
205
 
private static class CacheMap extends LinkedHashMap {
206
 
        private int maxsize = -1;
207
 
 
208
 
        CacheMap(int maxsize) {
209
 
                super(16, (float) 0.75, true);
210
 
                this.maxsize = maxsize;
211
 
        }
212
 
 
213
 
        int
214
 
        getMaxSize() {
215
 
                return maxsize;
216
 
        }
217
 
 
218
 
        void
219
 
        setMaxSize(int maxsize) {
220
 
                /*
221
 
                 * Note that this doesn't shrink the size of the map if
222
 
                 * the maximum size is lowered, but it should shrink as
223
 
                 * entries expire.
224
 
                 */
225
 
                this.maxsize = maxsize;
226
 
        }
227
 
 
228
 
        protected boolean removeEldestEntry(Map.Entry eldest) {
229
 
                return maxsize >= 0 && size() > maxsize;
230
 
        }
231
 
}
232
 
 
233
 
private CacheMap data;
234
 
private int maxncache = -1;
235
 
private int maxcache = -1;
236
 
private int dclass;
237
 
 
238
 
private static final int defaultMaxEntries = 50000;
239
 
 
240
 
/**
241
 
 * Creates an empty Cache
242
 
 *
243
 
 * @param dclass The DNS class of this cache
244
 
 * @see DClass
245
 
 */
246
 
public
247
 
Cache(int dclass) {
248
 
        this.dclass = dclass;
249
 
        data = new CacheMap(defaultMaxEntries);
250
 
}
251
 
 
252
 
/**
253
 
 * Creates an empty Cache for class IN.
254
 
 * @see DClass
255
 
 */
256
 
public
257
 
Cache() {
258
 
        this(DClass.IN);
259
 
}
260
 
 
261
 
/**
262
 
 * Creates a Cache which initially contains all records in the specified file.
263
 
 */
264
 
public
265
 
Cache(String file) throws IOException {
266
 
        data = new CacheMap(defaultMaxEntries);
267
 
        Master m = new Master(file);
268
 
        Record record;
269
 
        while ((record = m.nextRecord()) != null)
270
 
                addRecord(record, Credibility.HINT, m);
271
 
}
272
 
 
273
 
private synchronized Object
274
 
exactName(Name name) {
275
 
        return data.get(name);
276
 
}
277
 
 
278
 
private synchronized void
279
 
removeName(Name name) {
280
 
        data.remove(name);
281
 
}
282
 
 
283
 
private synchronized Element []
284
 
allElements(Object types) {
285
 
        if (types instanceof List) {
286
 
                List typelist = (List) types;
287
 
                int size = typelist.size();
288
 
                return (Element []) typelist.toArray(new Element[size]);
289
 
        } else {
290
 
                Element set = (Element) types;
291
 
                return new Element[] {set};
292
 
        }
293
 
}
294
 
 
295
 
private synchronized Element
296
 
oneElement(Name name, Object types, int type, int minCred) {
297
 
        Element found = null;
298
 
 
299
 
        if (type == Type.ANY)
300
 
                throw new IllegalArgumentException("oneElement(ANY)");
301
 
        if (types instanceof List) {
302
 
                List list = (List) types;
303
 
                for (int i = 0; i < list.size(); i++) {
304
 
                        Element set = (Element) list.get(i);
305
 
                        if (set.getType() == type) {
 
99
        private interface Element {
 
100
                public boolean expired();
 
101
                public int compareCredibility(int cred);
 
102
                public int getType();
 
103
        }
 
104
 
 
105
        private static int
 
106
        limitExpire(long ttl, long maxttl) {
 
107
                if (maxttl >= 0 && maxttl < ttl)
 
108
                        ttl = maxttl;
 
109
                int expire = (int)((System.currentTimeMillis() / 1000) + ttl);
 
110
                if (expire < 0 || expire > Integer.MAX_VALUE)
 
111
                        return Integer.MAX_VALUE;
 
112
                return expire;
 
113
        }
 
114
 
 
115
        private static class CacheRRset extends RRset implements Element {
 
116
                int credibility;
 
117
                int expire;
 
118
 
 
119
                public
 
120
                CacheRRset(Record rec, int cred, long maxttl) {
 
121
                        super();
 
122
                        this.credibility = cred;
 
123
                        this.expire = limitExpire(rec.getTTL(), maxttl);
 
124
                        addRR(rec);
 
125
                }
 
126
 
 
127
                public
 
128
                CacheRRset(RRset rrset, int cred, long maxttl) {
 
129
                        super(rrset);
 
130
                        this.credibility = cred;
 
131
                        this.expire = limitExpire(rrset.getTTL(), maxttl);
 
132
                }
 
133
 
 
134
                public final boolean
 
135
                expired() {
 
136
                        int now = (int)(System.currentTimeMillis() / 1000);
 
137
                        return (now >= expire);
 
138
                }
 
139
 
 
140
                public final int
 
141
                compareCredibility(int cred) {
 
142
                        return credibility - cred;
 
143
                }
 
144
 
 
145
                public String
 
146
                toString() {
 
147
                        StringBuffer sb = new StringBuffer();
 
148
                        sb.append(super.toString());
 
149
                        sb.append(" cl = ");
 
150
                        sb.append(credibility);
 
151
                        return sb.toString();
 
152
                }
 
153
        }
 
154
 
 
155
        private static class NegativeElement implements Element {
 
156
                int type;
 
157
                Name name;
 
158
                SOARecord soa;
 
159
                int credibility;
 
160
                int expire;
 
161
 
 
162
                public
 
163
                NegativeElement(Name name, int type, SOARecord soa, int cred,
 
164
                                long maxttl)
 
165
                {
 
166
                        this.name = name;
 
167
                        this.type = type;
 
168
                        this.soa = soa;
 
169
                        long cttl = 0;
 
170
                        if (soa != null)
 
171
                                cttl = soa.getMinimum();
 
172
                        this.credibility = cred;
 
173
                        this.expire = limitExpire(cttl, maxttl);
 
174
                }
 
175
 
 
176
                public int
 
177
                getType() {
 
178
                        return type;
 
179
                }
 
180
 
 
181
                public final boolean
 
182
                expired() {
 
183
                        int now = (int)(System.currentTimeMillis() / 1000);
 
184
                        return (now >= expire);
 
185
                }
 
186
 
 
187
                public final int
 
188
                compareCredibility(int cred) {
 
189
                        return credibility - cred;
 
190
                }
 
191
 
 
192
                public String
 
193
                toString() {
 
194
                        StringBuffer sb = new StringBuffer();
 
195
                        if (type == 0)
 
196
                                sb.append("NXDOMAIN " + name);
 
197
                        else
 
198
                                sb.append("NXRRSET " + name + " " + Type.string(type));
 
199
                        sb.append(" cl = ");
 
200
                        sb.append(credibility);
 
201
                        return sb.toString();
 
202
                }
 
203
        }
 
204
 
 
205
        private static class CacheMap extends LinkedHashMap {
 
206
                private int maxsize = -1;
 
207
 
 
208
                CacheMap(int maxsize) {
 
209
                        super(16, (float) 0.75, true);
 
210
                        this.maxsize = maxsize;
 
211
                }
 
212
 
 
213
                int
 
214
                getMaxSize() {
 
215
                        return maxsize;
 
216
                }
 
217
 
 
218
                void
 
219
                setMaxSize(int maxsize) {
 
220
                        /*
 
221
                         * Note that this doesn't shrink the size of the map if
 
222
                         * the maximum size is lowered, but it should shrink as
 
223
                         * entries expire.
 
224
                         */
 
225
                        this.maxsize = maxsize;
 
226
                }
 
227
 
 
228
                protected boolean removeEldestEntry(Map.Entry eldest) {
 
229
                        return maxsize >= 0 && size() > maxsize;
 
230
                }
 
231
        }
 
232
 
 
233
        private CacheMap data;
 
234
        private int maxncache = -1;
 
235
        private int maxcache = -1;
 
236
        private int dclass;
 
237
 
 
238
        private static final int defaultMaxEntries = 50000;
 
239
 
 
240
        /**
 
241
         * Creates an empty Cache
 
242
         *
 
243
         * @param dclass The DNS class of this cache
 
244
         * @see DClass
 
245
         */
 
246
        public
 
247
        Cache(int dclass) {
 
248
                this.dclass = dclass;
 
249
                data = new CacheMap(defaultMaxEntries);
 
250
        }
 
251
 
 
252
        /**
 
253
         * Creates an empty Cache for class IN.
 
254
         * @see DClass
 
255
         */
 
256
        public
 
257
        Cache() {
 
258
                this(DClass.IN);
 
259
        }
 
260
 
 
261
        /**
 
262
         * Creates a Cache which initially contains all records in the specified file.
 
263
         */
 
264
        public
 
265
        Cache(String file) throws IOException {
 
266
                data = new CacheMap(defaultMaxEntries);
 
267
                Master m = new Master(file);
 
268
                Record record;
 
269
                while ((record = m.nextRecord()) != null)
 
270
                        addRecord(record, Credibility.HINT, m);
 
271
        }
 
272
 
 
273
        private synchronized Object
 
274
        exactName(Name name) {
 
275
                return data.get(name);
 
276
        }
 
277
 
 
278
        private synchronized void
 
279
        removeName(Name name) {
 
280
                data.remove(name);
 
281
        }
 
282
 
 
283
        private synchronized Element []
 
284
                                      allElements(Object types) {
 
285
                if (types instanceof List) {
 
286
                        List typelist = (List) types;
 
287
                        int size = typelist.size();
 
288
                        return (Element []) typelist.toArray(new Element[size]);
 
289
                } else {
 
290
                        Element set = (Element) types;
 
291
                        return new Element[] {set};
 
292
                }
 
293
        }
 
294
 
 
295
        private synchronized Element
 
296
        oneElement(Name name, Object types, int type, int minCred) {
 
297
                Element found = null;
 
298
 
 
299
                if (type == Type.ANY)
 
300
                        throw new IllegalArgumentException("oneElement(ANY)");
 
301
                if (types instanceof List) {
 
302
                        List list = (List) types;
 
303
                        for (int i = 0; i < list.size(); i++) {
 
304
                                Element set = (Element) list.get(i);
 
305
                                if (set.getType() == type) {
 
306
                                        found = set;
 
307
                                        break;
 
308
                                }
 
309
                        }
 
310
                } else {
 
311
                        Element set = (Element) types;
 
312
                        if (set.getType() == type)
306
313
                                found = set;
307
 
                                break;
308
 
                        }
309
 
                }
310
 
        } else {
311
 
                Element set = (Element) types;
312
 
                if (set.getType() == type)
313
 
                        found = set;
314
 
        }
315
 
        if (found == null)
316
 
                return null;
317
 
        if (found.expired()) {
318
 
                removeElement(name, type);
319
 
                return null;
320
 
        }
321
 
        if (found.compareCredibility(minCred) < 0)
322
 
                return null;
323
 
        return found;
324
 
}
325
 
 
326
 
private synchronized Element
327
 
findElement(Name name, int type, int minCred) {
328
 
        Object types = exactName(name);
329
 
        if (types == null)
330
 
                return null;
331
 
        return oneElement(name, types, type, minCred);
332
 
}
333
 
 
334
 
private synchronized void
335
 
addElement(Name name, Element element) {
336
 
        Object types = data.get(name);
337
 
        if (types == null) {
338
 
                data.put(name, element);
339
 
                return;
340
 
        }
341
 
        int type = element.getType();
342
 
        if (types instanceof List) {
343
 
                List list = (List) types;
344
 
                for (int i = 0; i < list.size(); i++) {
345
 
                        Element elt = (Element) list.get(i);
346
 
                        if (elt.getType() == type) {
347
 
                                list.set(i, element);
348
 
                                return;
349
 
                        }
350
 
                }
351
 
                list.add(element);
352
 
        } else {
353
 
                Element elt = (Element) types;
354
 
                if (elt.getType() == type)
 
314
                }
 
315
                if (found == null)
 
316
                        return null;
 
317
                if (found.expired()) {
 
318
                        removeElement(name, type);
 
319
                        return null;
 
320
                }
 
321
                if (found.compareCredibility(minCred) < 0)
 
322
                        return null;
 
323
                return found;
 
324
        }
 
325
 
 
326
        private synchronized Element
 
327
        findElement(Name name, int type, int minCred) {
 
328
                Object types = exactName(name);
 
329
                if (types == null)
 
330
                        return null;
 
331
                return oneElement(name, types, type, minCred);
 
332
        }
 
333
 
 
334
        private synchronized void
 
335
        addElement(Name name, Element element) {
 
336
                Object types = data.get(name);
 
337
                if (types == null) {
355
338
                        data.put(name, element);
356
 
                else {
357
 
                        LinkedList list = new LinkedList();
358
 
                        list.add(elt);
 
339
                        return;
 
340
                }
 
341
                int type = element.getType();
 
342
                if (types instanceof List) {
 
343
                        List list = (List) types;
 
344
                        for (int i = 0; i < list.size(); i++) {
 
345
                                Element elt = (Element) list.get(i);
 
346
                                if (elt.getType() == type) {
 
347
                                        list.set(i, element);
 
348
                                        return;
 
349
                                }
 
350
                        }
359
351
                        list.add(element);
360
 
                        data.put(name, list);
 
352
                } else {
 
353
                        Element elt = (Element) types;
 
354
                        if (elt.getType() == type)
 
355
                                data.put(name, element);
 
356
                        else {
 
357
                                LinkedList list = new LinkedList();
 
358
                                list.add(elt);
 
359
                                list.add(element);
 
360
                                data.put(name, list);
 
361
                        }
361
362
                }
362
363
        }
363
 
}
364
364
 
365
 
private synchronized void
366
 
removeElement(Name name, int type) {
367
 
        Object types = data.get(name);
368
 
        if (types == null) {
369
 
                return;
370
 
        }
371
 
        if (types instanceof List) {
372
 
                List list = (List) types;
373
 
                for (int i = 0; i < list.size(); i++) {
374
 
                        Element elt = (Element) list.get(i);
375
 
                        if (elt.getType() == type) {
376
 
                                list.remove(i);
377
 
                                if (list.size() == 0)
378
 
                                        data.remove(name);
 
365
        private synchronized void
 
366
        removeElement(Name name, int type) {
 
367
                Object types = data.get(name);
 
368
                if (types == null) {
 
369
                        return;
 
370
                }
 
371
                if (types instanceof List) {
 
372
                        List list = (List) types;
 
373
                        for (int i = 0; i < list.size(); i++) {
 
374
                                Element elt = (Element) list.get(i);
 
375
                                if (elt.getType() == type) {
 
376
                                        list.remove(i);
 
377
                                        if (list.size() == 0)
 
378
                                                data.remove(name);
 
379
                                        return;
 
380
                                }
 
381
                        }
 
382
                } else {
 
383
                        Element elt = (Element) types;
 
384
                        if (elt.getType() != type)
379
385
                                return;
380
 
                        }
 
386
                        data.remove(name);
381
387
                }
382
 
        } else {
383
 
                Element elt = (Element) types;
384
 
                if (elt.getType() != type)
 
388
        }
 
389
 
 
390
        /** Empties the Cache. */
 
391
        public synchronized void
 
392
        clearCache() {
 
393
                data.clear();
 
394
        }
 
395
 
 
396
        /**
 
397
         * Adds a record to the Cache.
 
398
         * @param r The record to be added
 
399
         * @param cred The credibility of the record
 
400
         * @param o The source of the record (this could be a Message, for example)
 
401
         * @see Record
 
402
         */
 
403
        public synchronized void
 
404
        addRecord(Record r, int cred, Object o) {
 
405
                Name name = r.getName();
 
406
                int type = r.getRRsetType();
 
407
                if (!Type.isRR(type))
385
408
                        return;
386
 
                data.remove(name);
387
 
        }
388
 
}
389
 
 
390
 
/** Empties the Cache. */
391
 
public synchronized void
392
 
clearCache() {
393
 
        data.clear();
394
 
}
395
 
 
396
 
/**
397
 
 * Adds a record to the Cache.
398
 
 * @param r The record to be added
399
 
 * @param cred The credibility of the record
400
 
 * @param o The source of the record (this could be a Message, for example)
401
 
 * @see Record
402
 
 */
403
 
public synchronized void
404
 
addRecord(Record r, int cred, Object o) {
405
 
        Name name = r.getName();
406
 
        int type = r.getRRsetType();
407
 
        if (!Type.isRR(type))
408
 
                return;
409
 
        Element element = findElement(name, type, cred);
410
 
        if (element == null) {
411
 
                CacheRRset crrset = new CacheRRset(r, cred, maxcache);
412
 
                addRRset(crrset, cred);
413
 
        } else if (element.compareCredibility(cred) == 0) {
414
 
                if (element instanceof CacheRRset) {
415
 
                        CacheRRset crrset = (CacheRRset) element;
416
 
                        crrset.addRR(r);
417
 
                }
418
 
        }
419
 
}
420
 
 
421
 
/**
422
 
 * Adds an RRset to the Cache.
423
 
 * @param rrset The RRset to be added
424
 
 * @param cred The credibility of these records
425
 
 * @see RRset
426
 
 */
427
 
public synchronized void
428
 
addRRset(RRset rrset, int cred) {
429
 
        long ttl = rrset.getTTL();
430
 
        Name name = rrset.getName();
431
 
        int type = rrset.getType();
432
 
        Element element = findElement(name, type, 0);
433
 
        if (ttl == 0) {
434
 
                if (element != null && element.compareCredibility(cred) <= 0)
435
 
                        removeElement(name, type);
436
 
        } else {
437
 
                if (element != null && element.compareCredibility(cred) <= 0)
438
 
                        element = null;
 
409
                Element element = findElement(name, type, cred);
439
410
                if (element == null) {
440
 
                        CacheRRset crrset;
441
 
                        if (rrset instanceof CacheRRset)
442
 
                                crrset = (CacheRRset) rrset;
 
411
                        CacheRRset crrset = new CacheRRset(r, cred, maxcache);
 
412
                        addRRset(crrset, cred);
 
413
                } else if (element.compareCredibility(cred) == 0) {
 
414
                        if (element instanceof CacheRRset) {
 
415
                                CacheRRset crrset = (CacheRRset) element;
 
416
                                crrset.addRR(r);
 
417
                        }
 
418
                }
 
419
        }
 
420
 
 
421
        /**
 
422
         * Adds an RRset to the Cache.
 
423
         * @param rrset The RRset to be added
 
424
         * @param cred The credibility of these records
 
425
         * @see RRset
 
426
         */
 
427
        public synchronized void
 
428
        addRRset(RRset rrset, int cred) {
 
429
                long ttl = rrset.getTTL();
 
430
                Name name = rrset.getName();
 
431
                int type = rrset.getType();
 
432
                Element element = findElement(name, type, 0);
 
433
                if (ttl == 0) {
 
434
                        if (element != null && element.compareCredibility(cred) <= 0)
 
435
                                removeElement(name, type);
 
436
                } else {
 
437
                        if (element != null && element.compareCredibility(cred) <= 0)
 
438
                                element = null;
 
439
                        if (element == null) {
 
440
                                CacheRRset crrset;
 
441
                                if (rrset instanceof CacheRRset)
 
442
                                        crrset = (CacheRRset) rrset;
 
443
                                else
 
444
                                        crrset = new CacheRRset(rrset, cred, maxcache);
 
445
                                addElement(name, crrset);
 
446
                        }
 
447
                }
 
448
        }
 
449
 
 
450
        /**
 
451
         * Adds a negative entry to the Cache.
 
452
         * @param name The name of the negative entry
 
453
         * @param type The type of the negative entry
 
454
         * @param soa The SOA record to add to the negative cache entry, or null.
 
455
         * The negative cache ttl is derived from the SOA.
 
456
         * @param cred The credibility of the negative entry
 
457
         */
 
458
        public synchronized void
 
459
        addNegative(Name name, int type, SOARecord soa, int cred) {
 
460
                long ttl = 0;
 
461
                if (soa != null)
 
462
                        ttl = soa.getTTL();
 
463
                Element element = findElement(name, type, 0);
 
464
                if (ttl == 0) {
 
465
                        if (element != null && element.compareCredibility(cred) <= 0)
 
466
                                removeElement(name, type);
 
467
                } else {
 
468
                        if (element != null && element.compareCredibility(cred) <= 0)
 
469
                                element = null;
 
470
                        if (element == null)
 
471
                                addElement(name, new NegativeElement(name, type,
 
472
                                                soa, cred,
 
473
                                                maxncache));
 
474
                }
 
475
        }
 
476
 
 
477
        /**
 
478
         * Finds all matching sets or something that causes the lookup to stop.
 
479
         */
 
480
        protected synchronized SetResponse
 
481
        lookup(Name name, int type, int minCred) {
 
482
                int labels;
 
483
                int tlabels;
 
484
                Element element;
 
485
                Name tname;
 
486
                Object types;
 
487
                SetResponse sr;
 
488
 
 
489
                labels = name.labels();
 
490
 
 
491
                for (tlabels = labels; tlabels >= 1; tlabels--) {
 
492
                        boolean isRoot = (tlabels == 1);
 
493
                        boolean isExact = (tlabels == labels);
 
494
 
 
495
                        if (isRoot)
 
496
                                tname = Name.root;
 
497
                        else if (isExact)
 
498
                                tname = name;
443
499
                        else
444
 
                                crrset = new CacheRRset(rrset, cred, maxcache);
445
 
                        addElement(name, crrset);
446
 
                }
447
 
        }
448
 
}
449
 
 
450
 
/**
451
 
 * Adds a negative entry to the Cache.
452
 
 * @param name The name of the negative entry
453
 
 * @param type The type of the negative entry
454
 
 * @param soa The SOA record to add to the negative cache entry, or null.
455
 
 * The negative cache ttl is derived from the SOA.
456
 
 * @param cred The credibility of the negative entry
457
 
 */
458
 
public synchronized void
459
 
addNegative(Name name, int type, SOARecord soa, int cred) {
460
 
        long ttl = 0;
461
 
        if (soa != null)
462
 
                ttl = soa.getTTL();
463
 
        Element element = findElement(name, type, 0);
464
 
        if (ttl == 0) {
465
 
                if (element != null && element.compareCredibility(cred) <= 0)
466
 
                        removeElement(name, type);
467
 
        } else {
468
 
                if (element != null && element.compareCredibility(cred) <= 0)
469
 
                        element = null;
470
 
                if (element == null)
471
 
                        addElement(name, new NegativeElement(name, type,
472
 
                                                             soa, cred,
473
 
                                                             maxncache));
474
 
        }
475
 
}
476
 
 
477
 
/**
478
 
 * Finds all matching sets or something that causes the lookup to stop.
479
 
 */
480
 
protected synchronized SetResponse
481
 
lookup(Name name, int type, int minCred) {
482
 
        int labels;
483
 
        int tlabels;
484
 
        Element element;
485
 
        Name tname;
486
 
        Object types;
487
 
        SetResponse sr;
488
 
 
489
 
        labels = name.labels();
490
 
 
491
 
        for (tlabels = labels; tlabels >= 1; tlabels--) {
492
 
                boolean isRoot = (tlabels == 1);
493
 
                boolean isExact = (tlabels == labels);
494
 
 
495
 
                if (isRoot)
496
 
                        tname = Name.root;
497
 
                else if (isExact)
498
 
                        tname = name;
499
 
                else
500
 
                        tname = new Name(name, labels - tlabels);
501
 
 
502
 
                types = data.get(tname);
503
 
                if (types == null)
504
 
                        continue;
505
 
 
506
 
                /* If this is an ANY lookup, return everything. */
507
 
                if (isExact && type == Type.ANY) {
508
 
                        sr = new SetResponse(SetResponse.SUCCESSFUL);
509
 
                        Element [] elements = allElements(types);
510
 
                        int added = 0;
511
 
                        for (int i = 0; i < elements.length; i++) {
512
 
                                element = elements[i];
513
 
                                if (element.expired()) {
514
 
                                        removeElement(tname, element.getType());
515
 
                                        continue;
516
 
                                }
517
 
                                if (!(element instanceof CacheRRset))
518
 
                                        continue;
519
 
                                if (element.compareCredibility(minCred) < 0)
520
 
                                        continue;
521
 
                                sr.addRRset((CacheRRset)element);
522
 
                                added++;
523
 
                        }
524
 
                        /* There were positive entries */
525
 
                        if (added > 0)
526
 
                                return sr;
527
 
                }
528
 
 
529
 
                /*
530
 
                 * If this is the name, look for the actual type or a CNAME.
531
 
                 * Otherwise, look for a DNAME.
532
 
                 */
533
 
                if (isExact) {
534
 
                        element = oneElement(tname, types, type, minCred);
535
 
                        if (element != null &&
536
 
                            element instanceof CacheRRset)
537
 
                        {
 
500
                                tname = new Name(name, labels - tlabels);
 
501
 
 
502
                        types = data.get(tname);
 
503
                        if (types == null)
 
504
                                continue;
 
505
 
 
506
                        /* If this is an ANY lookup, return everything. */
 
507
                        if (isExact && type == Type.ANY) {
538
508
                                sr = new SetResponse(SetResponse.SUCCESSFUL);
539
 
                                sr.addRRset((CacheRRset) element);
540
 
                                return sr;
541
 
                        } else if (element != null) {
542
 
                                sr = new SetResponse(SetResponse.NXRRSET);
543
 
                                return sr;
544
 
                        }
545
 
 
546
 
                        element = oneElement(tname, types, Type.CNAME, minCred);
547
 
                        if (element != null &&
548
 
                            element instanceof CacheRRset)
549
 
                        {
550
 
                                return new SetResponse(SetResponse.CNAME,
551
 
                                                       (CacheRRset) element);
552
 
                        }
553
 
                } else {
554
 
                        element = oneElement(tname, types, Type.DNAME, minCred);
555
 
                        if (element != null &&
556
 
                            element instanceof CacheRRset)
557
 
                        {
558
 
                                return new SetResponse(SetResponse.DNAME,
559
 
                                                       (CacheRRset) element);
560
 
                        }
561
 
                }
562
 
 
563
 
                /* Look for an NS */
564
 
                element = oneElement(tname, types, Type.NS, minCred);
565
 
                if (element != null && element instanceof CacheRRset)
566
 
                        return new SetResponse(SetResponse.DELEGATION,
567
 
                                               (CacheRRset) element);
568
 
 
569
 
                /* Check for the special NXDOMAIN element. */
570
 
                if (isExact) {
571
 
                        element = oneElement(tname, types, 0, minCred);
572
 
                        if (element != null)
573
 
                                return SetResponse.ofType(SetResponse.NXDOMAIN);
574
 
                }
575
 
 
576
 
        }
577
 
        return SetResponse.ofType(SetResponse.UNKNOWN);
578
 
}
579
 
 
580
 
/**
581
 
 * Looks up Records in the Cache.  This follows CNAMEs and handles negatively
582
 
 * cached data.
583
 
 * @param name The name to look up
584
 
 * @param type The type to look up
585
 
 * @param minCred The minimum acceptable credibility
586
 
 * @return A SetResponse object
587
 
 * @see SetResponse
588
 
 * @see Credibility
589
 
 */
590
 
public SetResponse
591
 
lookupRecords(Name name, int type, int minCred) {
592
 
        return lookup(name, type, minCred);
593
 
}
594
 
 
595
 
private RRset []
596
 
findRecords(Name name, int type, int minCred) {
597
 
        SetResponse cr = lookupRecords(name, type, minCred);
598
 
        if (cr.isSuccessful())
599
 
                return cr.answers();
600
 
        else
601
 
                return null;
602
 
}
603
 
 
604
 
/**
605
 
 * Looks up credible Records in the Cache (a wrapper around lookupRecords).
606
 
 * Unlike lookupRecords, this given no indication of why failure occurred.
607
 
 * @param name The name to look up
608
 
 * @param type The type to look up
609
 
 * @return An array of RRsets, or null
610
 
 * @see Credibility
611
 
 */
612
 
public RRset []
613
 
findRecords(Name name, int type) {
614
 
        return findRecords(name, type, Credibility.NORMAL);
615
 
}
616
 
 
617
 
/**
618
 
 * Looks up Records in the Cache (a wrapper around lookupRecords).  Unlike
619
 
 * lookupRecords, this given no indication of why failure occurred.
620
 
 * @param name The name to look up
621
 
 * @param type The type to look up
622
 
 * @return An array of RRsets, or null
623
 
 * @see Credibility
624
 
 */
625
 
public RRset []
626
 
findAnyRecords(Name name, int type) {
627
 
        return findRecords(name, type, Credibility.GLUE);
628
 
}
629
 
 
630
 
private final int
631
 
getCred(int section, boolean isAuth) {
632
 
        if (section == Section.ANSWER) {
633
 
                if (isAuth)
634
 
                        return Credibility.AUTH_ANSWER;
635
 
                else
636
 
                        return Credibility.NONAUTH_ANSWER;
637
 
        } else if (section == Section.AUTHORITY) {
638
 
                if (isAuth)
639
 
                        return Credibility.AUTH_AUTHORITY;
640
 
                else
641
 
                        return Credibility.NONAUTH_AUTHORITY;
642
 
        } else if (section == Section.ADDITIONAL) {
643
 
                return Credibility.ADDITIONAL;
644
 
        } else
645
 
                throw new IllegalArgumentException("getCred: invalid section");
646
 
}
647
 
 
648
 
private static void
649
 
markAdditional(RRset rrset, Set names) {
650
 
        Record first = rrset.first();
651
 
        if (first.getAdditionalName() == null)
652
 
                return;
653
 
 
654
 
        Iterator it = rrset.rrs();
655
 
        while (it.hasNext()) {
656
 
                Record r = (Record) it.next();
657
 
                Name name = r.getAdditionalName();
658
 
                if (name != null)
659
 
                        names.add(name);
660
 
        }
661
 
}
662
 
 
663
 
/**
664
 
 * Adds all data from a Message into the Cache.  Each record is added with
665
 
 * the appropriate credibility, and negative answers are cached as such.
666
 
 * @param in The Message to be added
667
 
 * @return A SetResponse that reflects what would be returned from a cache
668
 
 * lookup, or null if nothing useful could be cached from the message.
669
 
 * @see Message
670
 
 */
671
 
public SetResponse
672
 
addMessage(Message in) {
673
 
        boolean isAuth = in.getHeader().getFlag(Flags.AA);
674
 
        Record question = in.getQuestion();
675
 
        Name qname;
676
 
        Name curname;
677
 
        int qtype;
678
 
        int qclass;
679
 
        int cred;
680
 
        int rcode = in.getHeader().getRcode();
681
 
        boolean completed = false;
682
 
        RRset [] answers, auth, addl;
683
 
        SetResponse response = null;
684
 
        boolean verbose = Options.check("verbosecache");
685
 
        HashSet additionalNames;
686
 
 
687
 
        if ((rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN) ||
688
 
            question == null)
689
 
                return null;
690
 
 
691
 
        qname = question.getName();
692
 
        qtype = question.getType();
693
 
        qclass = question.getDClass();
694
 
 
695
 
        curname = qname;
696
 
 
697
 
        additionalNames = new HashSet();
698
 
 
699
 
        answers = in.getSectionRRsets(Section.ANSWER);
700
 
        for (int i = 0; i < answers.length; i++) {
701
 
                if (answers[i].getDClass() != qclass)
702
 
                        continue;
703
 
                int type = answers[i].getType();
704
 
                Name name = answers[i].getName();
705
 
                cred = getCred(Section.ANSWER, isAuth);
706
 
                if ((type == qtype || qtype == Type.ANY) &&
707
 
                    name.equals(curname))
708
 
                {
709
 
                        addRRset(answers[i], cred);
710
 
                        completed = true;
711
 
                        if (curname == qname) {
 
509
                                Element [] elements = allElements(types);
 
510
                                int added = 0;
 
511
                                for (int i = 0; i < elements.length; i++) {
 
512
                                        element = elements[i];
 
513
                                        if (element.expired()) {
 
514
                                                removeElement(tname, element.getType());
 
515
                                                continue;
 
516
                                        }
 
517
                                        if (!(element instanceof CacheRRset))
 
518
                                                continue;
 
519
                                        if (element.compareCredibility(minCred) < 0)
 
520
                                                continue;
 
521
                                        sr.addRRset((CacheRRset)element);
 
522
                                        added++;
 
523
                                }
 
524
                                /* There were positive entries */
 
525
                                if (added > 0)
 
526
                                        return sr;
 
527
                        }
 
528
 
 
529
                        /*
 
530
                         * If this is the name, look for the actual type or a CNAME.
 
531
                         * Otherwise, look for a DNAME.
 
532
                         */
 
533
                        if (isExact) {
 
534
                                element = oneElement(tname, types, type, minCred);
 
535
                                if (element != null &&
 
536
                                                element instanceof CacheRRset)
 
537
                                {
 
538
                                        sr = new SetResponse(SetResponse.SUCCESSFUL);
 
539
                                        sr.addRRset((CacheRRset) element);
 
540
                                        return sr;
 
541
                                } else if (element != null) {
 
542
                                        sr = new SetResponse(SetResponse.NXRRSET);
 
543
                                        return sr;
 
544
                                }
 
545
 
 
546
                                element = oneElement(tname, types, Type.CNAME, minCred);
 
547
                                if (element != null &&
 
548
                                                element instanceof CacheRRset)
 
549
                                {
 
550
                                        return new SetResponse(SetResponse.CNAME,
 
551
                                                        (CacheRRset) element);
 
552
                                }
 
553
                        } else {
 
554
                                element = oneElement(tname, types, Type.DNAME, minCred);
 
555
                                if (element != null &&
 
556
                                                element instanceof CacheRRset)
 
557
                                {
 
558
                                        return new SetResponse(SetResponse.DNAME,
 
559
                                                        (CacheRRset) element);
 
560
                                }
 
561
                        }
 
562
 
 
563
                        /* Look for an NS */
 
564
                        element = oneElement(tname, types, Type.NS, minCred);
 
565
                        if (element != null && element instanceof CacheRRset)
 
566
                                return new SetResponse(SetResponse.DELEGATION,
 
567
                                                (CacheRRset) element);
 
568
 
 
569
                        /* Check for the special NXDOMAIN element. */
 
570
                        if (isExact) {
 
571
                                element = oneElement(tname, types, 0, minCred);
 
572
                                if (element != null)
 
573
                                        return SetResponse.ofType(SetResponse.NXDOMAIN);
 
574
                        }
 
575
 
 
576
                }
 
577
                return SetResponse.ofType(SetResponse.UNKNOWN);
 
578
        }
 
579
 
 
580
        /**
 
581
         * Looks up Records in the Cache.  This follows CNAMEs and handles negatively
 
582
         * cached data.
 
583
         * @param name The name to look up
 
584
         * @param type The type to look up
 
585
         * @param minCred The minimum acceptable credibility
 
586
         * @return A SetResponse object
 
587
         * @see SetResponse
 
588
         * @see Credibility
 
589
         */
 
590
        public SetResponse
 
591
        lookupRecords(Name name, int type, int minCred) {
 
592
                return lookup(name, type, minCred);
 
593
        }
 
594
 
 
595
        private RRset []
 
596
                       findRecords(Name name, int type, int minCred) {
 
597
                SetResponse cr = lookupRecords(name, type, minCred);
 
598
                if (cr.isSuccessful())
 
599
                        return cr.answers();
 
600
                else
 
601
                        return null;
 
602
        }
 
603
 
 
604
        /**
 
605
         * Looks up credible Records in the Cache (a wrapper around lookupRecords).
 
606
         * Unlike lookupRecords, this given no indication of why failure occurred.
 
607
         * @param name The name to look up
 
608
         * @param type The type to look up
 
609
         * @return An array of RRsets, or null
 
610
         * @see Credibility
 
611
         */
 
612
        public RRset []
 
613
                      findRecords(Name name, int type) {
 
614
                return findRecords(name, type, Credibility.NORMAL);
 
615
        }
 
616
 
 
617
        /**
 
618
         * Looks up Records in the Cache (a wrapper around lookupRecords).  Unlike
 
619
         * lookupRecords, this given no indication of why failure occurred.
 
620
         * @param name The name to look up
 
621
         * @param type The type to look up
 
622
         * @return An array of RRsets, or null
 
623
         * @see Credibility
 
624
         */
 
625
        public RRset []
 
626
                      findAnyRecords(Name name, int type) {
 
627
                return findRecords(name, type, Credibility.GLUE);
 
628
        }
 
629
 
 
630
        private final int
 
631
        getCred(int section, boolean isAuth) {
 
632
                if (section == Section.ANSWER) {
 
633
                        if (isAuth)
 
634
                                return Credibility.AUTH_ANSWER;
 
635
                        else
 
636
                                return Credibility.NONAUTH_ANSWER;
 
637
                } else if (section == Section.AUTHORITY) {
 
638
                        if (isAuth)
 
639
                                return Credibility.AUTH_AUTHORITY;
 
640
                        else
 
641
                                return Credibility.NONAUTH_AUTHORITY;
 
642
                } else if (section == Section.ADDITIONAL) {
 
643
                        return Credibility.ADDITIONAL;
 
644
                } else
 
645
                        throw new IllegalArgumentException("getCred: invalid section");
 
646
        }
 
647
 
 
648
        private static void
 
649
        markAdditional(RRset rrset, Set names) {
 
650
                Record first = rrset.first();
 
651
                if (first.getAdditionalName() == null)
 
652
                        return;
 
653
 
 
654
                Iterator it = rrset.rrs();
 
655
                while (it.hasNext()) {
 
656
                        Record r = (Record) it.next();
 
657
                        Name name = r.getAdditionalName();
 
658
                        if (name != null)
 
659
                                names.add(name);
 
660
                }
 
661
        }
 
662
 
 
663
        /**
 
664
         * Adds all data from a Message into the Cache.  Each record is added with
 
665
         * the appropriate credibility, and negative answers are cached as such.
 
666
         * @param in The Message to be added
 
667
         * @return A SetResponse that reflects what would be returned from a cache
 
668
         * lookup, or null if nothing useful could be cached from the message.
 
669
         * @see Message
 
670
         */
 
671
        public SetResponse
 
672
        addMessage(Message in) {
 
673
                boolean isAuth = in.getHeader().getFlag(Flags.AA);
 
674
                Record question = in.getQuestion();
 
675
                Name qname;
 
676
                Name curname;
 
677
                int qtype;
 
678
                int qclass;
 
679
                int cred;
 
680
                int rcode = in.getHeader().getRcode();
 
681
                boolean completed = false;
 
682
                RRset [] answers, auth, addl;
 
683
                SetResponse response = null;
 
684
                boolean verbose = Options.check("verbosecache");
 
685
                HashSet additionalNames;
 
686
 
 
687
                if ((rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN) ||
 
688
                                question == null)
 
689
                        return null;
 
690
 
 
691
                qname = question.getName();
 
692
                qtype = question.getType();
 
693
                qclass = question.getDClass();
 
694
 
 
695
                curname = qname;
 
696
 
 
697
                additionalNames = new HashSet();
 
698
 
 
699
                answers = in.getSectionRRsets(Section.ANSWER);
 
700
                for (int i = 0; i < answers.length; i++) {
 
701
                        if (answers[i].getDClass() != qclass)
 
702
                                continue;
 
703
                        int type = answers[i].getType();
 
704
                        Name name = answers[i].getName();
 
705
                        cred = getCred(Section.ANSWER, isAuth);
 
706
                        if ((type == qtype || qtype == Type.ANY) &&
 
707
                                        name.equals(curname))
 
708
                        {
 
709
                                addRRset(answers[i], cred);
 
710
                                completed = true;
 
711
                                if (curname != null && curname.equals(qname)) {
 
712
                                        if (response == null)
 
713
                                                response = new SetResponse(
 
714
                                                                SetResponse.SUCCESSFUL);
 
715
                                        response.addRRset(answers[i]);
 
716
                                }
 
717
                                markAdditional(answers[i], additionalNames);
 
718
                        } else if (type == Type.CNAME && name.equals(curname)) {
 
719
                                CNAMERecord cname;
 
720
                                addRRset(answers[i], cred);
 
721
                                if (curname != null && curname.equals(qname))
 
722
                                        response = new SetResponse(SetResponse.CNAME,
 
723
                                                        answers[i]);
 
724
                                cname = (CNAMERecord) answers[i].first();
 
725
                                curname = cname.getTarget();
 
726
                        } else if (type == Type.DNAME && curname != null && curname.subdomain(name)) {
 
727
                                DNAMERecord dname;
 
728
                                addRRset(answers[i], cred);
 
729
                                if (curname.equals(qname))
 
730
                                        response = new SetResponse(SetResponse.DNAME,
 
731
                                                        answers[i]);
 
732
                                dname = (DNAMERecord) answers[i].first();
 
733
                                try {
 
734
                                        curname = curname.fromDNAME(dname);
 
735
                                }
 
736
                                catch (NameTooLongException e) {
 
737
                                        break;
 
738
                                }
 
739
                        }
 
740
                }
 
741
 
 
742
                auth = in.getSectionRRsets(Section.AUTHORITY);
 
743
                RRset soa = null, ns = null;
 
744
                if(curname != null) {
 
745
                        for (int i = 0; i < auth.length; i++) {
 
746
                                if (auth[i].getType() == Type.SOA &&
 
747
                                                curname.subdomain(auth[i].getName()))
 
748
                                        soa = auth[i];
 
749
                                else if (auth[i].getType() == Type.NS &&
 
750
                                                curname.subdomain(auth[i].getName()))
 
751
                                        ns = auth[i];
 
752
                        }
 
753
                }
 
754
                if (!completed) {
 
755
                        /* This is a negative response or a referral. */
 
756
                        int cachetype = (rcode == Rcode.NXDOMAIN) ? 0 : qtype;
 
757
                        if (rcode == Rcode.NXDOMAIN || soa != null || ns == null) {
 
758
                                /* Negative response */
 
759
                                cred = getCred(Section.AUTHORITY, isAuth);
 
760
                                SOARecord soarec = null;
 
761
                                if (soa != null)
 
762
                                        soarec = (SOARecord) soa.first();
 
763
                                if(curname != null)
 
764
                                        addNegative(curname, cachetype, soarec, cred);
 
765
                                if (response == null) {
 
766
                                        int responseType;
 
767
                                        if (rcode == Rcode.NXDOMAIN)
 
768
                                                responseType = SetResponse.NXDOMAIN;
 
769
                                        else
 
770
                                                responseType = SetResponse.NXRRSET;
 
771
                                        response = SetResponse.ofType(responseType);
 
772
                                }
 
773
                                /* DNSSEC records are not cached. */
 
774
                        } else {
 
775
                                /* Referral response */
 
776
                                cred = getCred(Section.AUTHORITY, isAuth);
 
777
                                addRRset(ns, cred);
 
778
                                markAdditional(ns, additionalNames);
712
779
                                if (response == null)
713
780
                                        response = new SetResponse(
714
 
                                                        SetResponse.SUCCESSFUL);
715
 
                                response.addRRset(answers[i]);
716
 
                        }
717
 
                        markAdditional(answers[i], additionalNames);
718
 
                } else if (type == Type.CNAME && name.equals(curname)) {
719
 
                        CNAMERecord cname;
720
 
                        addRRset(answers[i], cred);
721
 
                        if (curname == qname)
722
 
                                response = new SetResponse(SetResponse.CNAME,
723
 
                                                           answers[i]);
724
 
                        cname = (CNAMERecord) answers[i].first();
725
 
                        curname = cname.getTarget();
726
 
                } else if (type == Type.DNAME && curname.subdomain(name)) {
727
 
                        DNAMERecord dname;
728
 
                        addRRset(answers[i], cred);
729
 
                        if (curname == qname)
730
 
                                response = new SetResponse(SetResponse.DNAME,
731
 
                                                           answers[i]);
732
 
                        dname = (DNAMERecord) answers[i].first();
733
 
                        try {
734
 
                                curname = curname.fromDNAME(dname);
735
 
                        }
736
 
                        catch (NameTooLongException e) {
737
 
                                break;
738
 
                        }
739
 
                }
740
 
        }
741
 
 
742
 
        auth = in.getSectionRRsets(Section.AUTHORITY);
743
 
        RRset soa = null, ns = null;
744
 
        for (int i = 0; i < auth.length; i++) {
745
 
                if (auth[i].getType() == Type.SOA &&
746
 
                    curname.subdomain(auth[i].getName()))
747
 
                        soa = auth[i];
748
 
                else if (auth[i].getType() == Type.NS &&
749
 
                         curname.subdomain(auth[i].getName()))
750
 
                        ns = auth[i];
751
 
        }
752
 
        if (!completed) {
753
 
                /* This is a negative response or a referral. */
754
 
                int cachetype = (rcode == Rcode.NXDOMAIN) ? 0 : qtype;
755
 
                if (rcode == Rcode.NXDOMAIN || soa != null || ns == null) {
756
 
                        /* Negative response */
757
 
                        cred = getCred(Section.AUTHORITY, isAuth);
758
 
                        SOARecord soarec = null;
759
 
                        if (soa != null)
760
 
                                soarec = (SOARecord) soa.first();
761
 
                        addNegative(curname, cachetype, soarec, cred);
762
 
                        if (response == null) {
763
 
                                int responseType;
764
 
                                if (rcode == Rcode.NXDOMAIN)
765
 
                                        responseType = SetResponse.NXDOMAIN;
766
 
                                else
767
 
                                        responseType = SetResponse.NXRRSET;
768
 
                                response = SetResponse.ofType(responseType);
769
 
                        }
770
 
                        /* DNSSEC records are not cached. */
771
 
                } else {
772
 
                        /* Referral response */
 
781
                                                        SetResponse.DELEGATION,
 
782
                                                        ns);
 
783
                        }
 
784
                } else if (rcode == Rcode.NOERROR && ns != null) {
 
785
                        /* Cache the NS set from a positive response. */
773
786
                        cred = getCred(Section.AUTHORITY, isAuth);
774
787
                        addRRset(ns, cred);
775
788
                        markAdditional(ns, additionalNames);
776
 
                        if (response == null)
777
 
                                response = new SetResponse(
778
 
                                                        SetResponse.DELEGATION,
779
 
                                                        ns);
780
 
                }
781
 
        } else if (rcode == Rcode.NOERROR && ns != null) {
782
 
                /* Cache the NS set from a positive response. */
783
 
                cred = getCred(Section.AUTHORITY, isAuth);
784
 
                addRRset(ns, cred);
785
 
                markAdditional(ns, additionalNames);
786
 
        }
787
 
 
788
 
        addl = in.getSectionRRsets(Section.ADDITIONAL);
789
 
        for (int i = 0; i < addl.length; i++) {
790
 
                int type = addl[i].getType();
791
 
                if (type != Type.A && type != Type.AAAA && type != Type.A6)
792
 
                        continue;
793
 
                Name name = addl[i].getName();
794
 
                if (!additionalNames.contains(name))
795
 
                        continue;
796
 
                cred = getCred(Section.ADDITIONAL, isAuth);
797
 
                addRRset(addl[i], cred);
798
 
        }
799
 
        if (verbose)
800
 
                System.out.println("addMessage: " + response);
801
 
        return (response);
802
 
}
803
 
 
804
 
/**
805
 
 * Flushes an RRset from the cache
806
 
 * @param name The name of the records to be flushed
807
 
 * @param type The type of the records to be flushed
808
 
 * @see RRset
809
 
 */
810
 
public void
811
 
flushSet(Name name, int type) {
812
 
        removeElement(name, type);
813
 
}
814
 
 
815
 
/**
816
 
 * Flushes all RRsets with a given name from the cache
817
 
 * @param name The name of the records to be flushed
818
 
 * @see RRset
819
 
 */
820
 
public void
821
 
flushName(Name name) {
822
 
        removeName(name);
823
 
}
824
 
 
825
 
/**
826
 
 * Sets the maximum length of time that a negative response will be stored
827
 
 * in this Cache.  A negative value disables this feature (that is, sets
828
 
 * no limit).
829
 
 */
830
 
public void
831
 
setMaxNCache(int seconds) {
832
 
        maxncache = seconds;
833
 
}
834
 
 
835
 
/**
836
 
 * Gets the maximum length of time that a negative response will be stored
837
 
 * in this Cache.  A negative value indicates no limit.
838
 
 */
839
 
public int
840
 
getMaxNCache() {
841
 
        return maxncache;
842
 
}
843
 
 
844
 
/**
845
 
 * Sets the maximum length of time that records will be stored in this
846
 
 * Cache.  A negative value disables this feature (that is, sets no limit).
847
 
 */
848
 
public void
849
 
setMaxCache(int seconds) {
850
 
        maxcache = seconds;
851
 
}
852
 
 
853
 
/**
854
 
 * Gets the maximum length of time that records will be stored
855
 
 * in this Cache.  A negative value indicates no limit.
856
 
 */
857
 
public int
858
 
getMaxCache() {
859
 
        return maxcache;
860
 
}
861
 
 
862
 
/**
863
 
 * Gets the current number of entries in the Cache, where an entry consists
864
 
 * of all records with a specific Name.
865
 
 */
866
 
public int
867
 
getSize() {
868
 
        return data.size();
869
 
}
870
 
 
871
 
/**
872
 
 * Gets the maximum number of entries in the Cache, where an entry consists
873
 
 * of all records with a specific Name.  A negative value is treated as an
874
 
 * infinite limit.
875
 
 */
876
 
public int
877
 
getMaxEntries() {
878
 
        return data.getMaxSize();
879
 
}
880
 
 
881
 
/**
882
 
 * Sets the maximum number of entries in the Cache, where an entry consists
883
 
 * of all records with a specific Name.  A negative value is treated as an
884
 
 * infinite limit.
885
 
 *
886
 
 * Note that setting this to a value lower than the current number
887
 
 * of entries will not cause the Cache to shrink immediately.
888
 
 *
889
 
 * The default maximum number of entries is 50000.
890
 
 *
891
 
 * @param entries The maximum number of entries in the Cache.
892
 
 */
893
 
public void
894
 
setMaxEntries(int entries) {
895
 
        data.setMaxSize(entries);
896
 
}
897
 
 
898
 
/**
899
 
 * Returns the DNS class of this cache.
900
 
 */
901
 
public int
902
 
getDClass() {
903
 
        return dclass;
904
 
}
905
 
 
906
 
/**
907
 
 * Returns the contents of the Cache as a string.
908
 
 */ 
909
 
public String
910
 
toString() {
911
 
        StringBuffer sb = new StringBuffer();
912
 
        synchronized (this) {
913
 
                Iterator it = data.values().iterator();
914
 
                while (it.hasNext()) {
915
 
                        Element [] elements = allElements(it.next());
916
 
                        for (int i = 0; i < elements.length; i++) {
917
 
                                sb.append(elements[i]);
918
 
                                sb.append("\n");
 
789
                }
 
790
 
 
791
                addl = in.getSectionRRsets(Section.ADDITIONAL);
 
792
                for (int i = 0; i < addl.length; i++) {
 
793
                        int type = addl[i].getType();
 
794
                        if (type != Type.A && type != Type.AAAA && type != Type.A6)
 
795
                                continue;
 
796
                        Name name = addl[i].getName();
 
797
                        if (!additionalNames.contains(name))
 
798
                                continue;
 
799
                        cred = getCred(Section.ADDITIONAL, isAuth);
 
800
                        addRRset(addl[i], cred);
 
801
                }
 
802
                if (verbose)
 
803
                        System.out.println("addMessage: " + response);
 
804
                return (response);
 
805
        }
 
806
 
 
807
        /**
 
808
         * Flushes an RRset from the cache
 
809
         * @param name The name of the records to be flushed
 
810
         * @param type The type of the records to be flushed
 
811
         * @see RRset
 
812
         */
 
813
        public void
 
814
        flushSet(Name name, int type) {
 
815
                removeElement(name, type);
 
816
        }
 
817
 
 
818
        /**
 
819
         * Flushes all RRsets with a given name from the cache
 
820
         * @param name The name of the records to be flushed
 
821
         * @see RRset
 
822
         */
 
823
        public void
 
824
        flushName(Name name) {
 
825
                removeName(name);
 
826
        }
 
827
 
 
828
        /**
 
829
         * Sets the maximum length of time that a negative response will be stored
 
830
         * in this Cache.  A negative value disables this feature (that is, sets
 
831
         * no limit).
 
832
         */
 
833
        public void
 
834
        setMaxNCache(int seconds) {
 
835
                maxncache = seconds;
 
836
        }
 
837
 
 
838
        /**
 
839
         * Gets the maximum length of time that a negative response will be stored
 
840
         * in this Cache.  A negative value indicates no limit.
 
841
         */
 
842
        public int
 
843
        getMaxNCache() {
 
844
                return maxncache;
 
845
        }
 
846
 
 
847
        /**
 
848
         * Sets the maximum length of time that records will be stored in this
 
849
         * Cache.  A negative value disables this feature (that is, sets no limit).
 
850
         */
 
851
        public void
 
852
        setMaxCache(int seconds) {
 
853
                maxcache = seconds;
 
854
        }
 
855
 
 
856
        /**
 
857
         * Gets the maximum length of time that records will be stored
 
858
         * in this Cache.  A negative value indicates no limit.
 
859
         */
 
860
        public int
 
861
        getMaxCache() {
 
862
                return maxcache;
 
863
        }
 
864
 
 
865
        /**
 
866
         * Gets the current number of entries in the Cache, where an entry consists
 
867
         * of all records with a specific Name.
 
868
         */
 
869
        public int
 
870
        getSize() {
 
871
                return data.size();
 
872
        }
 
873
 
 
874
        /**
 
875
         * Gets the maximum number of entries in the Cache, where an entry consists
 
876
         * of all records with a specific Name.  A negative value is treated as an
 
877
         * infinite limit.
 
878
         */
 
879
        public int
 
880
        getMaxEntries() {
 
881
                return data.getMaxSize();
 
882
        }
 
883
 
 
884
        /**
 
885
         * Sets the maximum number of entries in the Cache, where an entry consists
 
886
         * of all records with a specific Name.  A negative value is treated as an
 
887
         * infinite limit.
 
888
         *
 
889
         * Note that setting this to a value lower than the current number
 
890
         * of entries will not cause the Cache to shrink immediately.
 
891
         *
 
892
         * The default maximum number of entries is 50000.
 
893
         *
 
894
         * @param entries The maximum number of entries in the Cache.
 
895
         */
 
896
        public void
 
897
        setMaxEntries(int entries) {
 
898
                data.setMaxSize(entries);
 
899
        }
 
900
 
 
901
        /**
 
902
         * Returns the DNS class of this cache.
 
903
         */
 
904
        public int
 
905
        getDClass() {
 
906
                return dclass;
 
907
        }
 
908
 
 
909
        /**
 
910
         * Returns the contents of the Cache as a string.
 
911
         */ 
 
912
        public String
 
913
        toString() {
 
914
                StringBuffer sb = new StringBuffer();
 
915
                synchronized (this) {
 
916
                        Iterator it = data.values().iterator();
 
917
                        while (it.hasNext()) {
 
918
                                Element [] elements = allElements(it.next());
 
919
                                for (int i = 0; i < elements.length; i++) {
 
920
                                        sb.append(elements[i]);
 
921
                                        sb.append("\n");
 
922
                                }
919
923
                        }
920
924
                }
 
925
                return sb.toString();
921
926
        }
922
 
        return sb.toString();
923
 
}
924
927
 
925
928
}