• 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.78
/library/src/main/java/com/alibaba/dcm/internal/InetAddressCacheUtilForNew.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 java.lang.reflect.Constructor;
11
import java.lang.reflect.Field;
12
import java.lang.reflect.InvocationTargetException;
13
import java.net.InetAddress;
14
import java.net.UnknownHostException;
15
import java.util.ArrayList;
16
import java.util.Iterator;
17
import java.util.List;
18
import java.util.Map;
19
import java.util.concurrent.ConcurrentMap;
20
import java.util.concurrent.ConcurrentSkipListSet;
21

22
import static com.alibaba.dcm.internal.InetAddressCacheUtilCommons.*;
23
import static com.alibaba.dcm.internal.TimeUtil.convertNanoTimeToTimeMillis;
24
import static com.alibaba.dcm.internal.TimeUtil.getNanoTimeAfterMs;
25

26
/**
27
 * Util class to manipulate dns cache for new {@code JDK 9+}.
28
 * <p>
29
 * dns cache is {@link InetAddress#cache}.
30
 *
31
 * @author antfling (ding_zhengang at hithinksoft dot com)
32
 * @author Jerry Lee (oldratlee at gmail dot com)
33
 * @since 1.6.0
34
 */
35
@ParametersAreNonnullByDefault
36
@ReturnValuesAreNonnullByDefault
37
@ApiStatus.Internal
38
public final class InetAddressCacheUtilForNew {
39
    /**
40
     * {@link InetAddress.CachedAddresses}
41
     * <p>
42
     * For jdk9+,
43
     * <ul>
44
     * <li>need not convert host to lowercase.<br>
45
     *     see {@link InetAddress.CachedAddresses#CachedAddresses}.
46
     * <li>{@code final long expiryTime; // time of expiry (in terms of System.nanoTime()) }<br>
47
     *     see {@link InetAddress.CachedAddresses.expiryTime}.
48
     * </ul>
49
     */
50
    public static void setInetAddressCache(String host, String[] ips, long expireMillis)
51
            throws UnknownHostException, IllegalAccessException, InstantiationException,
52
            InvocationTargetException, ClassNotFoundException, NoSuchFieldException {
53
        long expiration = expireMillis == NEVER_EXPIRATION ? NEVER_EXPIRATION : getNanoTimeAfterMs(expireMillis);
1✔
54
        Object cachedAddresses = newCachedAddresses(host, ips, expiration);
1✔
55

56
        getCacheOfInetAddress().put(host, cachedAddresses);
1✔
57
        getExpirySetOfInetAddress().add(cachedAddresses);
1✔
58
    }
1✔
59

60
    /**
61
     * {@link InetAddress.CachedAddresses#CachedAddresses(String, InetAddress[], long)}
62
     */
63
    private static Object newCachedAddresses(String host, String[] ips, long expiration)
64
            throws ClassNotFoundException, UnknownHostException, IllegalAccessException,
65
            InvocationTargetException, InstantiationException {
66
        // InetAddress.CachedAddresses has only one constructor
67
        return getConstructorOfInetAddress$CachedAddresses().newInstance(host, toInetAddressArray(host, ips), expiration);
1✔
68
    }
69

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

75
    private static Constructor<?> getConstructorOfInetAddress$CachedAddresses() throws ClassNotFoundException {
76
        if (constructorOfInetAddress$CachedAddresses != null) return constructorOfInetAddress$CachedAddresses;
1✔
77

78
        synchronized (InetAddressCacheUtilCommons.class) {
1✔
79
            // double check
80
            if (constructorOfInetAddress$CachedAddresses != null) return constructorOfInetAddress$CachedAddresses;
1✔
81

82
            final Class<?> clazz = Class.forName(inetAddress$CachedAddresses_ClassName);
1✔
83

84
            // InetAddress.CacheEntry has only one constructor:
85
            //
86
            // - for jdk 9-jdk12, constructor signature is CachedAddresses(String host, InetAddress[] inetAddresses, long expiryTime)
87
            // code in jdk 9:
88
            //   https://hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/java.base/share/classes/java/net/InetAddress.java#l783
89
            // code in jdk 11:
90
            //   https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/net/InetAddress.java#l787
91
            final Constructor<?> constructor = clazz.getDeclaredConstructors()[0];
1✔
92
            constructor.setAccessible(true);
1✔
93

94
            constructorOfInetAddress$CachedAddresses = constructor;
1✔
95
            return constructor;
1✔
96
        }
97
    }
98

99
    public static void removeInetAddressCache(String host) throws NoSuchFieldException, IllegalAccessException {
100
        removeHostFromExpirySetOfInetAddress(host);
1✔
101
        getCacheOfInetAddress().remove(host);
1✔
102
    }
1✔
103

104
    /**
105
     * @see #getExpirySetOfInetAddress()
106
     */
107
    private static void removeHostFromExpirySetOfInetAddress(String host)
108
            throws NoSuchFieldException, IllegalAccessException {
109
        for (Iterator<Object> iterator = getExpirySetOfInetAddress().iterator(); iterator.hasNext(); ) {
1✔
110
            Object cachedAddresses = iterator.next();
1✔
111
            if (getHostOfInetAddress$CacheAddress(cachedAddresses).equals(host)) {
1✔
112
                iterator.remove();
1✔
113
            }
114
        }
1✔
115
    }
1✔
116

117
    private static volatile Field hostFieldOfInetAddress$CacheAddress = null;
1✔
118

119
    /**
120
     * {@link InetAddress.CachedAddresses.host}
121
     */
122
    private static String getHostOfInetAddress$CacheAddress(Object cachedAddresses)
123
            throws NoSuchFieldException, IllegalAccessException {
124
        if (hostFieldOfInetAddress$CacheAddress == null) {
1✔
125
            synchronized (InetAddressCacheUtilForNew.class) {
1✔
126
                if (hostFieldOfInetAddress$CacheAddress == null) { // double check
1✔
127
                    final Field f = cachedAddresses.getClass().getDeclaredField("host");
1✔
128
                    f.setAccessible(true);
1✔
129
                    hostFieldOfInetAddress$CacheAddress = f;
1✔
130
                }
131
            }
1✔
132
        }
133
        return (String) hostFieldOfInetAddress$CacheAddress.get(cachedAddresses);
1✔
134
    }
135

136

137
    //////////////////////////////////////////////////////////////////////////////
138
    // getters of static cache related fields of InetAddress
139
    //////////////////////////////////////////////////////////////////////////////
140

141
    /**
142
     * return {@link InetAddress.cache} field.
143
     * <ul>
144
     * <li>type is {@code ConcurrentHashMap<String, Addresses>} type and thread-safe.
145
     * <li>contains values of type interface {@link InetAddress.Addresses}.
146
     * </ul>
147
     */
148
    @SuppressWarnings("unchecked")
149
    private static ConcurrentMap<String, Object> getCacheOfInetAddress()
150
            throws NoSuchFieldException, IllegalAccessException {
151
        return (ConcurrentMap<String, Object>) getCacheAndExpirySetOfInetAddress0()[0];
1✔
152
    }
153

154
    /**
155
     * @return {@link InetAddress.expirySet} field.
156
     * <p>
157
     * type is {@code ConcurrentSkipListSet<CachedAddresses>} and thread-safe.
158
     */
159
    @SuppressWarnings("unchecked")
160
    private static ConcurrentSkipListSet<Object> getExpirySetOfInetAddress()
161
            throws NoSuchFieldException, IllegalAccessException {
162
        return (ConcurrentSkipListSet<Object>) getCacheAndExpirySetOfInetAddress0()[1];
1✔
163
    }
164

165
    private static volatile Object[] ADDRESS_CACHE_AND_EXPIRY_SET = null;
1✔
166

167
    /**
168
     * @return {@link InetAddress#cache} and {@link InetAddress#expirySet}
169
     */
170
    private static Object[] getCacheAndExpirySetOfInetAddress0()
171
            throws NoSuchFieldException, IllegalAccessException {
172
        if (ADDRESS_CACHE_AND_EXPIRY_SET != null) return ADDRESS_CACHE_AND_EXPIRY_SET;
1✔
173

174
        synchronized (InetAddressCacheUtilForNew.class) {
1✔
175
            if (ADDRESS_CACHE_AND_EXPIRY_SET != null) return ADDRESS_CACHE_AND_EXPIRY_SET;
1✔
176

177
            final Field cacheField = InetAddress.class.getDeclaredField("cache");
1✔
178
            cacheField.setAccessible(true);
1✔
179

180
            final Field expirySetField = InetAddress.class.getDeclaredField("expirySet");
1✔
181
            expirySetField.setAccessible(true);
1✔
182

183
            ADDRESS_CACHE_AND_EXPIRY_SET = new Object[]{
1✔
184
                    cacheField.get(InetAddress.class),
1✔
185
                    expirySetField.get(InetAddress.class)
1✔
186
            };
187

188
            return ADDRESS_CACHE_AND_EXPIRY_SET;
1✔
189
        }
190
    }
191

192
    //////////////////////////////////////////////////////////////////////////////
193

194

195
    @Nullable
196
    public static DnsCacheEntry getInetAddressCache(String host)
197
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
198
        final Object addresses = getCacheOfInetAddress().get(host);
1✔
199
        if (null == addresses) {
1✔
200
            return null;
1✔
201
        }
202

203
        return inetAddress$Addresses2DnsCacheEntry(host, addresses);
1✔
204
    }
205

206
    public static DnsCache listInetAddressCache()
207
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
208
        final List<DnsCacheEntry> retCache = new ArrayList<>();
1✔
209
        final List<DnsCacheEntry> retNegativeCache = new ArrayList<>();
1✔
210

211
        final ConcurrentMap<String, Object> cache = getCacheOfInetAddress();
1✔
212
        for (Map.Entry<String, Object> entry : cache.entrySet()) {
1✔
213
            final String host = entry.getKey();
1✔
214

215
            DnsCacheEntry dnsCacheEntry = inetAddress$Addresses2DnsCacheEntry(host, entry.getValue());
1✔
216
            if (dnsCacheEntry.getIps().length == 0) {
1✔
217
                retNegativeCache.add(dnsCacheEntry);
1✔
218
            } else {
219
                retCache.add(dnsCacheEntry);
1✔
220
            }
221
        }
1✔
222

223
        return new DnsCache(retCache, retNegativeCache);
1✔
224
    }
225

226
    /**
227
     * convert {@link InetAddress.Addresses} to {@link DnsCacheEntry}
228
     */
229
    private static DnsCacheEntry inetAddress$Addresses2DnsCacheEntry(String host, Object addresses)
230
            throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
231
        final String addressesClassName = addresses.getClass().getName();
1✔
232

233
        initFieldsOfAddresses();
1✔
234

235
        final InetAddress[] inetAddresses;
236
        final long expiration;
237
        if (addressesClassName.equals(inetAddress$CachedAddresses_ClassName)) {
1✔
238
            inetAddresses = (InetAddress[]) inetAddressesFieldOfInetAddress$CacheAddress.get(addresses);
1✔
239

240
            long expiryTimeNanos = expiryTimeFieldOfInetAddress$CacheAddress.getLong(addresses);
1✔
241
            expiration = convertNanoTimeToTimeMillis(expiryTimeNanos);
1✔
242
        } else if (addressesClassName.equals(inetAddress$NameServiceAddresses_ClassName)) {
1✔
243
            throw new IllegalStateException("child class " + addressesClassName +
×
244
                    " for class InetAddress.Addresses should never happens, report issue for dns-cache-manipulator lib!");
245
        } else {
246
            throw new IllegalStateException("JDK add new child class " + addressesClassName +
×
247
                    " for class InetAddress.Addresses, report issue for dns-cache-manipulator lib!");
248
        }
249

250
        final String[] ips = getIpFromInetAddress(inetAddresses);
1✔
251

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

255
    private static final String inetAddress$CachedAddresses_ClassName = "java.net.InetAddress$CachedAddresses";
256
    private static final String inetAddress$NameServiceAddresses_ClassName = "java.net.InetAddress$NameServiceAddresses";
257

258
    // Fields of InetAddress$CachedAddresses
259
    /**
260
     * {@link InetAddress.CachedAddresses.inetAddresses}
261
     */
262
    private static volatile Field inetAddressesFieldOfInetAddress$CacheAddress = null;
1✔
263
    /**
264
     * {@link InetAddress.CachedAddresses.expiryTime}
265
     */
266
    private static volatile Field expiryTimeFieldOfInetAddress$CacheAddress = null;
1✔
267

268
    private static void initFieldsOfAddresses() throws ClassNotFoundException, NoSuchFieldException {
269
        if (inetAddressesFieldOfInetAddress$CacheAddress != null) return;
1✔
270

271
        synchronized (InetAddressCacheUtilForNew.class) {
1✔
272
            if (inetAddressesFieldOfInetAddress$CacheAddress != null) return;
1✔
273

274
            ///////////////////////////////////////////////
275
            // Fields of InetAddress$CachedAddresses
276
            ///////////////////////////////////////////////
277
            final Class<?> cachedAddresses_Class = Class.forName(inetAddress$CachedAddresses_ClassName);
1✔
278

279
            final Field inetAddressesFiled = cachedAddresses_Class.getDeclaredField("inetAddresses");
1✔
280
            inetAddressesFiled.setAccessible(true);
1✔
281
            inetAddressesFieldOfInetAddress$CacheAddress = inetAddressesFiled;
1✔
282

283
            final Field expiryTimeFiled = cachedAddresses_Class.getDeclaredField("expiryTime");
1✔
284
            expiryTimeFiled.setAccessible(true);
1✔
285
            expiryTimeFieldOfInetAddress$CacheAddress = expiryTimeFiled;
1✔
286
        }
1✔
287
    }
1✔
288

289
    public static void clearInetAddressCache() throws NoSuchFieldException, IllegalAccessException {
290
        getExpirySetOfInetAddress().clear();
1✔
291
        getCacheOfInetAddress().clear();
1✔
292
    }
1✔
293

294
    private InetAddressCacheUtilForNew() {
295
    }
296
}
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