1 /* 2 * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.net.dns; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.concurrent.TimeUnit; 31 32 /* 33 * An implementation of sun.net.ResolverConfiguration for Windows. 34 */ 35 36 public class ResolverConfigurationImpl 37 extends ResolverConfiguration 38 { 39 // Lock held whilst loading configuration or checking 40 private static Object lock = new Object(); 41 42 // Resolver options 43 private final Options opts; 44 45 // Addresses have changed. We default to true to make sure we 46 // resolve the first time it is requested. 47 private static boolean changed = true; 48 49 // Time of last refresh. 50 private static long lastRefresh; 51 52 // Cache timeout (120 seconds) - should be converted into property 53 // or configured as preference in the future. 54 private static final long TIMEOUT_NANOS = TimeUnit.SECONDS.toNanos(120); 55 56 // DNS suffix list and name servers populated by native method 57 private static String os_searchlist; 58 private static String os_nameservers; 59 60 // Cached lists 61 private static ArrayList<String> searchlist; 62 private static ArrayList<String> nameservers; 63 64 // Parse string that consists of token delimited by comma 65 // and return ArrayList. Refer to ResolverConfigurationImpl.c and 66 // strappend to see how the string is created. 67 private ArrayList<String> stringToList(String str) { 68 // String is delimited by comma. 69 String[] tokens = str.split(","); 70 ArrayList<String> l = new ArrayList<>(tokens.length); 71 for (String s : tokens) { 72 if (!s.isEmpty() && !l.contains(s)) { 73 l.add(s); 74 } 75 } 76 l.trimToSize(); 77 return l; 78 } 79 80 // Parse string that consists of token delimited by comma 81 // and return ArrayList. Refer to ResolverConfigurationImpl.c and 82 // strappend to see how the string is created. 83 // In addition to splitting the string, converts IPv6 addresses to 84 // BSD-style. 85 private ArrayList<String> addressesToList(String str) { 86 // String is delimited by comma 87 String[] tokens = str.split(","); 88 ArrayList<String> l = new ArrayList<>(tokens.length); 89 90 for (String s : tokens) { 91 if (!s.isEmpty()) { 92 if (s.indexOf(':') >= 0 && s.charAt(0) != '[') { 93 // Not BSD style 94 s = '[' + s + ']'; 95 } 96 if (!s.isEmpty() && !l.contains(s)) { 97 l.add(s); 98 } 99 } 100 } 101 l.trimToSize(); 102 return l; 103 } 104 105 // Load DNS configuration from OS 106 107 private void loadConfig() { 108 assert Thread.holdsLock(lock); 109 110 // A change in the network address of the machine usually indicates 111 // a change in DNS configuration too so we always refresh the config 112 // after such a change. 113 if (changed) { 114 changed = false; 115 } else { 116 // Otherwise we refresh if TIMEOUT_NANOS has passed since last 117 // load. 118 long currTime = System.nanoTime(); 119 // lastRefresh will always have been set once because we start with 120 // changed = true. 121 if ((currTime - lastRefresh) < TIMEOUT_NANOS) { 122 return; 123 } 124 } 125 126 // Native code that uses Windows API to find out the DNS server 127 // addresses and search suffixes. It builds a comma-delimited string 128 // of nameservers and domain suffixes and sets them to the static 129 // os_nameservers and os_searchlist. We then split these into Java 130 // Lists here. 131 loadDNSconfig0(); 132 133 // Record the time of update and refresh the lists of addresses / 134 // domain suffixes. 135 lastRefresh = System.nanoTime(); 136 searchlist = stringToList(os_searchlist); 137 nameservers = addressesToList(os_nameservers); 138 os_searchlist = null; // can be GC'ed 139 os_nameservers = null; 140 } 141 142 ResolverConfigurationImpl() { 143 opts = new OptionsImpl(); 144 } 145 146 @SuppressWarnings("unchecked") // clone() 147 public List<String> searchlist() { 148 synchronized (lock) { 149 loadConfig(); 150 151 // List is mutable so return a shallow copy 152 return (List<String>)searchlist.clone(); 153 } 154 } 155 156 @SuppressWarnings("unchecked") // clone() 157 public List<String> nameservers() { 158 synchronized (lock) { 159 loadConfig(); 160 161 // List is mutable so return a shallow copy 162 return (List<String>)nameservers.clone(); 163 } 164 } 165 166 public Options options() { 167 return opts; 168 } 169 170 // --- Address Change Listener 171 172 static class AddressChangeListener extends Thread { 173 public void run() { 174 for (;;) { 175 // wait for configuration to change 176 if (notifyAddrChange0() != 0) 177 return; 178 synchronized (lock) { 179 changed = true; 180 } 181 } 182 } 183 } 184 185 186 // --- Native methods -- 187 188 static native void init0(); 189 190 static native void loadDNSconfig0(); 191 192 static native int notifyAddrChange0(); 193 194 static { 195 jdk.internal.loader.BootLoader.loadLibrary("net"); 196 init0(); 197 198 // start the address listener thread 199 AddressChangeListener thr = new AddressChangeListener(); 200 thr.setDaemon(true); 201 thr.start(); 202 } 203 } 204 205 /** 206 * Implementation of {@link ResolverConfiguration.Options} 207 */ 208 class OptionsImpl extends ResolverConfiguration.Options { 209 }