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 final DnsQueryContextMap contexts = getOrCreateContextMap(nameServerAddr);
50 return contexts.add(qCtx);
51 }
52
53
54
55
56
57
58
59
60
61 DnsQueryContext get(InetSocketAddress nameServerAddr, int id) {
62 final DnsQueryContextMap contexts = getContextMap(nameServerAddr);
63 if (contexts == null) {
64 return null;
65 }
66 return contexts.get(id);
67 }
68
69
70
71
72
73
74
75
76
77 DnsQueryContext remove(InetSocketAddress nameServerAddr, int id) {
78 final DnsQueryContextMap contexts = getContextMap(nameServerAddr);
79 if (contexts == null) {
80 return null;
81 }
82 return contexts.remove(id);
83 }
84
85 private DnsQueryContextMap getContextMap(InetSocketAddress nameServerAddr) {
86 synchronized (map) {
87 return map.get(nameServerAddr);
88 }
89 }
90
91 private DnsQueryContextMap getOrCreateContextMap(InetSocketAddress nameServerAddr) {
92 synchronized (map) {
93 final DnsQueryContextMap contexts = map.get(nameServerAddr);
94 if (contexts != null) {
95 return contexts;
96 }
97
98 final DnsQueryContextMap newContexts = new DnsQueryContextMap();
99 final InetAddress a = nameServerAddr.getAddress();
100 final int port = nameServerAddr.getPort();
101 DnsQueryContextMap old = map.put(nameServerAddr, newContexts);
102
103 assert old == null : "DnsQueryContextMap already exists for " + nameServerAddr;
104
105 InetSocketAddress extraAddress = null;
106 if (a instanceof Inet4Address) {
107
108 final Inet4Address a4 = (Inet4Address) a;
109 if (a4.isLoopbackAddress()) {
110 extraAddress = new InetSocketAddress(NetUtil.LOCALHOST6, port);
111 } else {
112 extraAddress = new InetSocketAddress(toCompactAddress(a4), port);
113 }
114 } else if (a instanceof Inet6Address) {
115
116 final Inet6Address a6 = (Inet6Address) a;
117 if (a6.isLoopbackAddress()) {
118 extraAddress = new InetSocketAddress(NetUtil.LOCALHOST4, port);
119 } else if (a6.isIPv4CompatibleAddress()) {
120 extraAddress = new InetSocketAddress(toIPv4Address(a6), port);
121 }
122 }
123 if (extraAddress != null) {
124 old = map.put(extraAddress, newContexts);
125
126 assert old == null : "DnsQueryContextMap already exists for " + extraAddress;
127 }
128
129 return newContexts;
130 }
131 }
132
133 private static Inet6Address toCompactAddress(Inet4Address a4) {
134 byte[] b4 = a4.getAddress();
135 byte[] b6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, b4[0], b4[1], b4[2], b4[3] };
136 try {
137 return (Inet6Address) InetAddress.getByAddress(b6);
138 } catch (UnknownHostException e) {
139 throw new Error(e);
140 }
141 }
142
143 private static Inet4Address toIPv4Address(Inet6Address a6) {
144 assert a6.isIPv4CompatibleAddress();
145
146 byte[] b6 = a6.getAddress();
147 byte[] b4 = { b6[12], b6[13], b6[14], b6[15] };
148 try {
149 return (Inet4Address) InetAddress.getByAddress(b4);
150 } catch (UnknownHostException e) {
151 throw new Error(e);
152 }
153 }
154
155 private static final class DnsQueryContextMap {
156
157 private final DnsQueryIdSpace idSpace = new DnsQueryIdSpace();
158
159
160 private final IntObjectMap<DnsQueryContext> map = new IntObjectHashMap<DnsQueryContext>();
161
162 synchronized int add(DnsQueryContext ctx) {
163 int id = idSpace.nextId();
164 DnsQueryContext oldCtx = map.put(id, ctx);
165 assert oldCtx == null;
166 return id;
167 }
168
169 synchronized DnsQueryContext get(int id) {
170 return map.get(id);
171 }
172
173 synchronized DnsQueryContext remove(int id) {
174 idSpace.pushId(id);
175 return map.remove(id);
176 }
177 }
178 }