• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alibaba / java-dns-cache-manipulator / 1267

pending completion
1267

push

Appveyor

oldratlee
chore(ci): upgrade CI JDK 🤖

527 of 645 relevant lines covered (81.71%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.96
/library/src/main/java/com/alibaba/dcm/internal/InetAddressCacheUtilForOld.java
1
package com.alibaba.dcm.internal;
2

3
import com.alibaba.dcm.DnsCache;
4
import com.alibaba.dcm.DnsCacheEntry;
5
import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault;
6
import org.jetbrains.annotations.ApiStatus;
7

8
import javax.annotation.Nullable;
9
import javax.annotation.ParametersAreNonnullByDefault;
10
import javax.annotation.concurrent.GuardedBy;
11
import java.lang.reflect.Constructor;
12
import java.lang.reflect.Field;
13
import java.lang.reflect.InvocationTargetException;
14
import java.net.InetAddress;
15
import java.net.UnknownHostException;
16
import java.util.ArrayList;
17
import java.util.HashMap;
18
import java.util.List;
19
import java.util.Map;
20

21
import static com.alibaba.dcm.internal.InetAddressCacheUtilCommons.*;
22

23
/**
24
 * Util class to manipulate dns cache for old {@code JDK 8-}.
25
 * <p>
26
 * dns cache is {@link InetAddress.Cache#cache} in {@link InetAddress#addressCache}.
27
 * <p>
28
 * <b>Caution</b>: <br>
29
 * Manipulation on {@link InetAddress#addressCache} <strong>MUST</strong>
30
 * be guarded by {@link InetAddress#addressCache} to avoid multithreading problem,
31
 * you can see the implementation of {@link InetAddress} to confirm this
32
 * (<b><i>See Also</i></b> lists key code of {@link InetAddress} related to this point).
33
 *
34
 * @author Jerry Lee (oldratlee at gmail dot com)
35
 * @see InetAddress
36
 * @see InetAddress#addressCache
37
 * @see InetAddress.CacheEntry
38
 * @see InetAddress#cacheInitIfNeeded()
39
 * @see InetAddress#cacheAddresses(String, InetAddress[], boolean)
40
 */
41
@ParametersAreNonnullByDefault
42
@ReturnValuesAreNonnullByDefault
43
@ApiStatus.Internal
44
public final class InetAddressCacheUtilForOld {
45
    /**
46
     * Need convert host to lowercase, see {@link InetAddress#cacheAddresses(String, InetAddress[], boolean)}.
47
     */
48
    public static void setInetAddressCache(String host, String[] ips, long expireMillis)
49
            throws UnknownHostException, IllegalAccessException, InstantiationException,
50
            InvocationTargetException, ClassNotFoundException, NoSuchFieldException {
51
        host = host.toLowerCase();
1✔
52
        long expiration = expireMillis == NEVER_EXPIRATION ? NEVER_EXPIRATION : System.currentTimeMillis() + expireMillis;
1✔
53
        Object entry = newCacheEntry(host, ips, expiration);
1✔
54

55
        synchronized (getAddressCacheOfInetAddress()) {
1✔
56
            getCache().put(host, entry);
1✔
57
            getNegativeCache().remove(host);
1✔
58
        }
1✔
59
    }
1✔
60

61
    private static Object newCacheEntry(String host, String[] ips, long expiration)
62
            throws UnknownHostException, ClassNotFoundException, IllegalAccessException,
63
            InvocationTargetException, InstantiationException {
64
        // InetAddress.CacheEntry has only one constructor
65
        return getConstructorOfInetAddress$CacheEntry().newInstance(toInetAddressArray(host, ips), expiration);
1✔
66
    }
67

68
    /**
69
     * {@link InetAddress.CacheEntry#CacheEntry}
70
     */
71
    private static volatile Constructor<?> constructorOfInetAddress$CacheEntry = null;
1✔
72

73
    private static Constructor<?> getConstructorOfInetAddress$CacheEntry() throws ClassNotFoundException {
74
        if (constructorOfInetAddress$CacheEntry != null) return constructorOfInetAddress$CacheEntry;
1✔
75

76
        synchronized (InetAddressCacheUtilCommons.class) {
1✔
77
            // double check
78
            if (constructorOfInetAddress$CacheEntry != null) return constructorOfInetAddress$CacheEntry;
1✔
79

80
            final String className = "java.net.InetAddress$CacheEntry";
1✔
81
            final Class<?> clazz = Class.forName(className);
1✔
82

83
            // InetAddress.CacheEntry has only one constructor:
84
            // - for jdk 6, constructor signature is CacheEntry(Object address, long expiration)
85
            // - for jdk 7/8+, constructor signature is CacheEntry(InetAddress[] addresses, long expiration)
86
            //
87
            // code in jdk 6:
88
            //   https://hg.openjdk.java.net/jdk6/jdk6/jdk/file/8deef18bb749/src/share/classes/java/net/InetAddress.java#l739
89
            // code in jdk 7:
90
            //   https://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/4dd5e486620d/src/share/classes/java/net/InetAddress.java#l742
91
            // code in jdk 8:
92
            //   https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/45e4e636b757/src/share/classes/java/net/InetAddress.java#l748
93
            final Constructor<?> constructor = clazz.getDeclaredConstructors()[0];
1✔
94
            constructor.setAccessible(true);
1✔
95

96
            constructorOfInetAddress$CacheEntry = constructor;
1✔
97
            return constructor;
1✔
98
        }
99
    }
100

101
    public static void removeInetAddressCache(String host)
102
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
103
        host = host.toLowerCase();
1✔
104

105
        synchronized (getAddressCacheOfInetAddress()) {
1✔
106
            getCache().remove(host);
1✔
107
            getNegativeCache().remove(host);
1✔
108
        }
1✔
109
    }
1✔
110

111
    /**
112
     * @return {@link InetAddress.Cache#cache} in {@link InetAddress#addressCache}
113
     */
114
    @GuardedBy("getAddressCacheOfInetAddress()")
115
    private static Map<String, Object> getCache()
116
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
117
        return getCacheOfInetAddress$Cache0(getAddressCacheOfInetAddress());
1✔
118
    }
119

120
    /**
121
     * @return {@link InetAddress.Cache#cache} in {@link InetAddress#negativeCache}
122
     */
123
    @GuardedBy("getAddressCacheOfInetAddress()")
124
    private static Map<String, Object> getNegativeCache()
125
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
126
        return getCacheOfInetAddress$Cache0(getNegativeCacheOfInetAddress());
1✔
127
    }
128

129

130
    /**
131
     * {@link InetAddress.Cache.cache}
132
     */
133
    private static volatile Field cacheMapFieldOfInetAddress$Cache = null;
1✔
134

135
    @SuppressWarnings("unchecked")
136
    private static Map<String, Object> getCacheOfInetAddress$Cache0(Object inetAddressCache)
137
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
138
        if (cacheMapFieldOfInetAddress$Cache == null) {
1✔
139
            synchronized (InetAddressCacheUtilForOld.class) {
1✔
140
                if (cacheMapFieldOfInetAddress$Cache == null) { // double check
1✔
141
                    final Class<?> clazz = Class.forName("java.net.InetAddress$Cache");
1✔
142
                    final Field f = clazz.getDeclaredField("cache");
1✔
143
                    f.setAccessible(true);
1✔
144
                    cacheMapFieldOfInetAddress$Cache = f;
1✔
145
                }
146
            }
1✔
147
        }
148

149
        return (Map<String, Object>) cacheMapFieldOfInetAddress$Cache.get(inetAddressCache);
1✔
150
    }
151

152
    /**
153
     * @return {@link InetAddress#addressCache}
154
     */
155
    private static Object getAddressCacheOfInetAddress()
156
            throws NoSuchFieldException, IllegalAccessException {
157
        return getAddressCacheAndNegativeCacheOfInetAddress0()[0];
1✔
158
    }
159

160
    /**
161
     * @return {@link InetAddress#negativeCache}
162
     */
163
    private static Object getNegativeCacheOfInetAddress()
164
            throws NoSuchFieldException, IllegalAccessException {
165
        return getAddressCacheAndNegativeCacheOfInetAddress0()[1];
1✔
166
    }
167

168
    private static volatile Object[] ADDRESS_CACHE_AND_NEGATIVE_CACHE = null;
1✔
169

170
    /**
171
     * @return {@link InetAddress#addressCache} and {@link InetAddress#negativeCache}
172
     */
173
    private static Object[] getAddressCacheAndNegativeCacheOfInetAddress0()
174
            throws NoSuchFieldException, IllegalAccessException {
175
        if (ADDRESS_CACHE_AND_NEGATIVE_CACHE != null) return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
1✔
176

177
        synchronized (InetAddressCacheUtilForOld.class) {
1✔
178
            // double check
179
            if (ADDRESS_CACHE_AND_NEGATIVE_CACHE != null) return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
1✔
180

181
            final Field cacheField = InetAddress.class.getDeclaredField("addressCache");
1✔
182
            cacheField.setAccessible(true);
1✔
183

184
            final Field negativeCacheField = InetAddress.class.getDeclaredField("negativeCache");
1✔
185
            negativeCacheField.setAccessible(true);
1✔
186

187
            ADDRESS_CACHE_AND_NEGATIVE_CACHE = new Object[]{
1✔
188
                    cacheField.get(InetAddress.class),
1✔
189
                    negativeCacheField.get(InetAddress.class)
1✔
190
            };
191
            return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
1✔
192
        }
193
    }
194

195
    @Nullable
196
    public static DnsCacheEntry getInetAddressCache(String host)
197
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
198
        host = host.toLowerCase();
1✔
199

200
        final Object cacheEntry;
201
        synchronized (getAddressCacheOfInetAddress()) {
1✔
202
            cacheEntry = getCache().get(host);
1✔
203
        }
1✔
204

205
        if (null == cacheEntry) return null;
1✔
206

207
        final DnsCacheEntry dnsCacheEntry = inetAddress$CacheEntry2DnsCacheEntry(host, cacheEntry);
1✔
208
        if (isDnsCacheEntryExpired(dnsCacheEntry.getHost())) return null;
1✔
209

210
        return dnsCacheEntry;
1✔
211
    }
212

213
    private static boolean isDnsCacheEntryExpired(@Nullable String host) {
214
        return null == host || "0.0.0.0".equals(host);
1✔
215
    }
216

217
    public static DnsCache listInetAddressCache()
218
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
219
        final Map<String, Object> cache;
220
        final Map<String, Object> negativeCache;
221
        synchronized (getAddressCacheOfInetAddress()) {
1✔
222
            cache = new HashMap<>(getCache());
1✔
223
            negativeCache = new HashMap<>(getNegativeCache());
1✔
224
        }
1✔
225

226
        return new DnsCache(convert(cache), convert(negativeCache));
1✔
227
    }
228

229
    private static List<DnsCacheEntry> convert(Map<String, Object> cache)
230
            throws IllegalAccessException, ClassNotFoundException, NoSuchFieldException {
231
        final List<DnsCacheEntry> ret = new ArrayList<>();
1✔
232
        for (Map.Entry<String, Object> entry : cache.entrySet()) {
1✔
233
            final String host = entry.getKey();
1✔
234
            if (isDnsCacheEntryExpired(host)) { // exclude expired entries!
1✔
235
                continue;
×
236
            }
237

238
            ret.add(inetAddress$CacheEntry2DnsCacheEntry(host, entry.getValue()));
1✔
239
        }
1✔
240
        return ret;
1✔
241
    }
242

243
    private static DnsCacheEntry inetAddress$CacheEntry2DnsCacheEntry(String host, Object entry)
244
            throws IllegalAccessException, ClassNotFoundException, NoSuchFieldException {
245
        initFieldsOfInetAddress$CacheEntry();
1✔
246

247
        final long expiration = expirationFieldOfInetAddress$CacheEntry.getLong(entry);
1✔
248

249
        final InetAddress[] addresses = (InetAddress[]) addressesFieldOfInetAddress$CacheEntry.get(entry);
1✔
250
        final String[] ips = getIpFromInetAddress(addresses);
1✔
251

252
        return new DnsCacheEntry(host, ips, expiration);
1✔
253
    }
254

255
    /**
256
     * {@link InetAddress.CacheEntry.expiration}
257
     */
258
    private static volatile Field expirationFieldOfInetAddress$CacheEntry = null;
1✔
259
    /**
260
     * {@link InetAddress.CacheEntry.addresses}
261
     */
262
    private static volatile Field addressesFieldOfInetAddress$CacheEntry = null;
1✔
263

264
    private static void initFieldsOfInetAddress$CacheEntry() throws ClassNotFoundException, NoSuchFieldException {
265
        if (expirationFieldOfInetAddress$CacheEntry != null && addressesFieldOfInetAddress$CacheEntry != null) return;
1✔
266

267
        synchronized (InetAddressCacheUtilForOld.class) {
1✔
268
            final Class<?> cacheEntryClass = Class.forName("java.net.InetAddress$CacheEntry");
1✔
269
            // double check
270
            if (expirationFieldOfInetAddress$CacheEntry != null && addressesFieldOfInetAddress$CacheEntry != null)
1✔
271
                return;
×
272

273
            // InetAddress.CacheEntry has 2 filed:
274
            // - for jdk 6, address and expiration
275
            // - for jdk 7+, addresses(*renamed*!) and expiration
276
            //
277
            // code in jdk 6:
278
            //   https://hg.openjdk.java.net/jdk6/jdk6/jdk/file/8deef18bb749/src/share/classes/java/net/InetAddress.java#l739
279
            // code in jdk 7:
280
            //   https://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/4dd5e486620d/src/share/classes/java/net/InetAddress.java#l742
281
            // code in jdk 8:
282
            //   https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/45e4e636b757/src/share/classes/java/net/InetAddress.java#l748
283

284
            Field expirationField = cacheEntryClass.getDeclaredField("expiration");
1✔
285
            expirationField.setAccessible(true);
1✔
286
            expirationFieldOfInetAddress$CacheEntry = expirationField;
1✔
287

288
            Field addressesField = cacheEntryClass.getDeclaredField("addresses");
1✔
289
            addressesField.setAccessible(true);
1✔
290
            addressesFieldOfInetAddress$CacheEntry = addressesField;
1✔
291
        }
1✔
292
    }
1✔
293

294
    public static void clearInetAddressCache()
295
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
296
        synchronized (getAddressCacheOfInetAddress()) {
1✔
297
            getCache().clear();
1✔
298
            getNegativeCache().clear();
1✔
299
        }
1✔
300
    }
1✔
301

302
    private InetAddressCacheUtilForOld() {
303
    }
304
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc