1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty.resolver.dns;
18
19 import io.netty.util.NetUtil;
20 import io.netty.util.collection.IntObjectHashMap;
21 import io.netty.util.collection.IntObjectMap;
22
23 import java.net.Inet4Address;
24 import java.net.Inet6Address;
25 import java.net.InetAddress;
26 import java.net.InetSocketAddress;
27 import java.net.UnknownHostException;
28 import java.util.HashMap;
29 import java.util.Map;
30
31 final class DnsQueryContextManager {
32
33
34
35
36
37 private final Map<InetSocketAddress, DnsQueryContextMap> map =
38 new HashMap<InetSocketAddress, DnsQueryContextMap>();
39
40
41
42
43
44
45
46
47
48 int add(InetSocketAddress nameServerAddr, DnsQueryContext qCtx) {
49 assert !nameServerAddr.isUnresolved();
50 final DnsQueryContextMap contexts = getOrCreateContextMap(nameServerAddr);
51 return contexts.add(qCtx);
52 }
53
54
55
56
57
58
59
60
61
62 DnsQueryContext get(InetSocketAddress nameServerAddr, int id) {
63 assert !nameServerAddr.isUnresolved();
64 final DnsQueryContextMap contexts = getContextMap(nameServerAddr);
65 if (contexts == null) {
66 return null;
67 }
68 return contexts.get(id);
69 }
70
71
72
73
74
75
76
77
78
79 DnsQueryContext remove(InetSocketAddress nameServerAddr, int id) {
80 assert !nameServerAddr.isUnresolved();
81 final DnsQueryContextMap contexts = getContextMap(nameServerAddr);
82 if (contexts == null) {
83 return null;
84 }
85 return contexts.remove(id);
86 }
87
88 private DnsQueryContextMap getContextMap(InetSocketAddress nameServerAddr) {
89 synchronized (map) {
90 return map.get(nameServerAddr);
91 }
92 }
93
94 private DnsQueryContextMap getOrCreateContextMap(InetSocketAddress nameServerAddr) {
95 synchronized (map) {
96 final DnsQueryContextMap contexts = map.get(nameServerAddr);
97 if (contexts != null) {
98 return contexts;
99 }
100
101 final DnsQueryContextMap newContexts = new DnsQueryContextMap();
102 final InetAddress a = nameServerAddr.getAddress();
103 final int port = nameServerAddr.getPort();
104 DnsQueryContextMap old = map.put(nameServerAddr, newContexts);
105
106 assert old == null : "DnsQueryContextMap already exists for " + nameServerAddr;
107
108 InetSocketAddress extraAddress = null;
109 if (a instanceof Inet4Address) {
110
111 final Inet4Address a4 = (Inet4Address) a;
112 if (a4.isLoopbackAddress()) {
113 extraAddress = new InetSocketAddress(NetUtil.LOCALHOST6, port);
114 } else {
115 extraAddress = new InetSocketAddress(toCompactAddress(a4), port);
116 }
117 } else if (a instanceof Inet6Address) {
118
119 final Inet6Address a6 = (Inet6Address) a;
120 if (a6.isLoopbackAddress()) {
121 extraAddress = new InetSocketAddress(NetUtil.LOCALHOST4, port);
122 } else if (a6.isIPv4CompatibleAddress()) {
123 extraAddress = new InetSocketAddress(toIPv4Address(a6), port);
124 }
125 }
126 if (extraAddress != null) {
127 old = map.put(extraAddress, newContexts);
128
129 assert old == null : "DnsQueryContextMap already exists for " + extraAddress;
130 }
131
132 return newContexts;
133 }
134 }
135
136 private static Inet6Address toCompactAddress(Inet4Address a4) {
137 byte[] b4 = a4.getAddress();
138 byte[] b6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b4[0], b4[1], b4[2], b4[3] };
139 try {
140 return (Inet6Address) InetAddress.getByAddress(b6);
141 } catch (UnknownHostException e) {
142 throw new Error(e);
143 }
144 }
145
146 private static Inet4Address toIPv4Address(Inet6Address a6) {
147 assert a6.isIPv4CompatibleAddress();
148
149 byte[] b6 = a6.getAddress();
150 byte[] b4 = { b6[12], b6[13], b6[14], b6[15] };
151 try {
152 return (Inet4Address) InetAddress.getByAddress(b4);
153 } catch (UnknownHostException e) {
154 throw new Error(e);
155 }
156 }
157
158 private static final class DnsQueryContextMap {
159
160 private final DnsQueryIdSpace idSpace = new DnsQueryIdSpace();
161
162
163 private final IntObjectMap<DnsQueryContext> map = new IntObjectHashMap<DnsQueryContext>();
164
165 synchronized int add(DnsQueryContext ctx) {
166 int id = idSpace.nextId();
167 if (id == -1) {
168
169
170 return -1;
171 }
172 DnsQueryContext oldCtx = map.put(id, ctx);
173 assert oldCtx == null;
174 return id;
175 }
176
177 synchronized DnsQueryContext get(int id) {
178 return map.get(id);
179 }
180
181 synchronized DnsQueryContext remove(int id) {
182 DnsQueryContext result = map.remove(id);
183 if (result != null) {
184 idSpace.pushId(id);
185 }
186 assert result != null : "DnsQueryContext not found, id: " + id;
187 return result;
188 }
189 }
190 }