1/*
2 * Copyright (c) 2002, 2012, 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
26package sun.net.dns;
27
28import java.util.List;
29import java.util.LinkedList;
30import java.util.StringTokenizer;
31
32/*
33 * An implementation of sun.net.ResolverConfiguration for Windows.
34 */
35
36public class ResolverConfigurationImpl
37    extends ResolverConfiguration
38{
39    // Lock helds whilst loading configuration or checking
40    private static Object lock = new Object();
41
42    // Resolver options
43    private final Options opts;
44
45    // Addreses have changed
46    private static boolean changed = false;
47
48    // Time of last refresh.
49    private static long lastRefresh = -1;
50
51    // Cache timeout (120 seconds) - should be converted into property
52    // or configured as preference in the future.
53    private static final int TIMEOUT = 120000;
54
55    // DNS suffix list and name servers populated by native method
56    private static String os_searchlist;
57    private static String os_nameservers;
58
59    // Cached lists
60    private static LinkedList<String> searchlist;
61    private static LinkedList<String> nameservers;
62
63    // Parse string that consists of token delimited by space or commas
64    // and return LinkedHashMap
65    private LinkedList<String> stringToList(String str) {
66        LinkedList<String> ll = new LinkedList<>();
67
68        // comma and space are valid delimites
69        StringTokenizer st = new StringTokenizer(str, ", ");
70        while (st.hasMoreTokens()) {
71            String s = st.nextToken();
72            if (!ll.contains(s)) {
73                ll.add(s);
74            }
75        }
76        return ll;
77    }
78
79    // Load DNS configuration from OS
80
81    private void loadConfig() {
82        assert Thread.holdsLock(lock);
83
84        // if address have changed then DNS probably changed aswell;
85        // otherwise check if cached settings have expired.
86        //
87        if (changed) {
88            changed = false;
89        } else {
90            if (lastRefresh >= 0) {
91                long currTime = System.currentTimeMillis();
92                if ((currTime - lastRefresh) < TIMEOUT) {
93                    return;
94                }
95            }
96        }
97
98        // load DNS configuration, update timestamp, create
99        // new HashMaps from the loaded configuration
100        //
101        loadDNSconfig0();
102
103        lastRefresh = System.currentTimeMillis();
104        searchlist = stringToList(os_searchlist);
105        nameservers = stringToList(os_nameservers);
106        os_searchlist = null;                       // can be GC'ed
107        os_nameservers = null;
108    }
109
110    ResolverConfigurationImpl() {
111        opts = new OptionsImpl();
112    }
113
114    @SuppressWarnings("unchecked") // clone()
115    public List<String> searchlist() {
116        synchronized (lock) {
117            loadConfig();
118
119            // List is mutable so return a shallow copy
120            return (List<String>)searchlist.clone();
121        }
122    }
123
124    @SuppressWarnings("unchecked") // clone()
125    public List<String> nameservers() {
126        synchronized (lock) {
127            loadConfig();
128
129            // List is mutable so return a shallow copy
130            return (List<String>)nameservers.clone();
131         }
132    }
133
134    public Options options() {
135        return opts;
136    }
137
138    // --- Address Change Listener
139
140    static class AddressChangeListener extends Thread {
141        public void run() {
142            for (;;) {
143                // wait for configuration to change
144                if (notifyAddrChange0() != 0)
145                    return;
146                synchronized (lock) {
147                    changed = true;
148                }
149            }
150        }
151    }
152
153
154    // --- Native methods --
155
156    static native void init0();
157
158    static native void loadDNSconfig0();
159
160    static native int notifyAddrChange0();
161
162    static {
163        java.security.AccessController.doPrivileged(
164            new java.security.PrivilegedAction<Void>() {
165                public Void run() {
166                    System.loadLibrary("net");
167                    return null;
168                }
169            });
170        init0();
171
172        // start the address listener thread
173        AddressChangeListener thr = new AddressChangeListener();
174        thr.setDaemon(true);
175        thr.start();
176    }
177}
178
179/**
180 * Implementation of {@link ResolverConfiguration.Options}
181 */
182class OptionsImpl extends ResolverConfiguration.Options {
183}
184