1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.resolver.dns;
17
18 import io.netty5.channel.EventLoop;
19 import io.netty5.handler.codec.dns.DnsRecord;
20 import io.netty5.util.internal.StringUtil;
21
22 import java.net.InetAddress;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.concurrent.ConcurrentMap;
26
27 import static io.netty5.util.internal.ObjectUtil.checkPositiveOrZero;
28 import static java.util.Objects.requireNonNull;
29
30
31
32
33
34 public class DefaultDnsCache implements DnsCache {
35
36 private final Cache<DefaultDnsCacheEntry> resolveCache = new Cache<>() {
37
38 @Override
39 protected boolean shouldReplaceAll(DefaultDnsCacheEntry entry) {
40 return entry.cause() != null;
41 }
42
43 @Override
44 protected boolean equals(DefaultDnsCacheEntry entry, DefaultDnsCacheEntry otherEntry) {
45 if (entry.address() != null) {
46 return entry.address().equals(otherEntry.address());
47 }
48 if (otherEntry.address() != null) {
49 return false;
50 }
51 return entry.cause().equals(otherEntry.cause());
52 }
53 };
54
55 private final int minTtl;
56 private final int maxTtl;
57 private final int negativeTtl;
58
59
60
61
62
63 public DefaultDnsCache() {
64 this(0, Cache.MAX_SUPPORTED_TTL_SECS, 0);
65 }
66
67
68
69
70
71
72
73 public DefaultDnsCache(int minTtl, int maxTtl, int negativeTtl) {
74 this.minTtl = Math.min(Cache.MAX_SUPPORTED_TTL_SECS, checkPositiveOrZero(minTtl, "minTtl"));
75 this.maxTtl = Math.min(Cache.MAX_SUPPORTED_TTL_SECS, checkPositiveOrZero(maxTtl, "maxTtl"));
76 if (minTtl > maxTtl) {
77 throw new IllegalArgumentException(
78 "minTtl: " + minTtl + ", maxTtl: " + maxTtl + " (expected: 0 <= minTtl <= maxTtl)");
79 }
80 this.negativeTtl = checkPositiveOrZero(negativeTtl, "negativeTtl");
81 }
82
83
84
85
86
87
88 public int minTtl() {
89 return minTtl;
90 }
91
92
93
94
95
96
97 public int maxTtl() {
98 return maxTtl;
99 }
100
101
102
103
104
105 public int negativeTtl() {
106 return negativeTtl;
107 }
108
109 @Override
110 public void clear() {
111 resolveCache.clear();
112 }
113
114 @Override
115 public boolean clear(String hostname) {
116 requireNonNull(hostname, "hostname");
117 return resolveCache.clear(appendDot(hostname));
118 }
119
120 private static boolean emptyAdditionals(DnsRecord[] additionals) {
121 return additionals == null || additionals.length == 0;
122 }
123
124 @Override
125 public List<? extends DnsCacheEntry> get(String hostname, DnsRecord[] additionals) {
126 requireNonNull(hostname, "hostname");
127 if (!emptyAdditionals(additionals)) {
128 return Collections.emptyList();
129 }
130
131 return resolveCache.get(appendDot(hostname));
132 }
133
134 @Override
135 public DnsCacheEntry cache(String hostname, DnsRecord[] additionals,
136 InetAddress address, long originalTtl, EventLoop loop) {
137 requireNonNull(hostname, "hostname");
138 requireNonNull(address, "address");
139 requireNonNull(loop, "loop");
140 DefaultDnsCacheEntry e = new DefaultDnsCacheEntry(hostname, address);
141 if (maxTtl == 0 || !emptyAdditionals(additionals)) {
142 return e;
143 }
144 resolveCache.cache(appendDot(hostname), e, Math.max(minTtl, (int) Math.min(maxTtl, originalTtl)), loop);
145 return e;
146 }
147
148 @Override
149 public DnsCacheEntry cache(String hostname, DnsRecord[] additionals, Throwable cause, EventLoop loop) {
150 requireNonNull(hostname, "hostname");
151 requireNonNull(cause, "cause");
152 requireNonNull(loop, "loop");
153
154 DefaultDnsCacheEntry e = new DefaultDnsCacheEntry(hostname, cause);
155 if (negativeTtl == 0 || !emptyAdditionals(additionals)) {
156 return e;
157 }
158
159 resolveCache.cache(appendDot(hostname), e, negativeTtl, loop);
160 return e;
161 }
162
163 @Override
164 public String toString() {
165 return new StringBuilder()
166 .append("DefaultDnsCache(minTtl=")
167 .append(minTtl).append(", maxTtl=")
168 .append(maxTtl).append(", negativeTtl=")
169 .append(negativeTtl).append(", cached resolved hostname=")
170 .append(resolveCache.size()).append(')')
171 .toString();
172 }
173
174 private static final class DefaultDnsCacheEntry implements DnsCacheEntry {
175 private final String hostname;
176 private final InetAddress address;
177 private final Throwable cause;
178
179 DefaultDnsCacheEntry(String hostname, InetAddress address) {
180 this.hostname = hostname;
181 this.address = address;
182 cause = null;
183 }
184
185 DefaultDnsCacheEntry(String hostname, Throwable cause) {
186 this.hostname = hostname;
187 this.cause = cause;
188 address = null;
189 }
190
191 @Override
192 public InetAddress address() {
193 return address;
194 }
195
196 @Override
197 public Throwable cause() {
198 return cause;
199 }
200
201 String hostname() {
202 return hostname;
203 }
204
205 @Override
206 public String toString() {
207 if (cause != null) {
208 return hostname + '/' + cause;
209 } else {
210 return address.toString();
211 }
212 }
213 }
214
215 private static String appendDot(String hostname) {
216 return StringUtil.endsWith(hostname, '.') ? hostname : hostname + '.';
217 }
218 }