1/*
2 * Copyright (c) 2001, 2011, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 4482446
27 * @summary java.net.SocketTimeoutException on 98, NT, 2000 for JSSE
28 * @run main/othervm ReuseAddr
29 *
30 *     SunJSSE does not support dynamic system properties, no way to re-use
31 *     system properties in samevm/agentvm mode.
32 * @author Brad Wetmore
33 */
34
35import java.io.*;
36import java.net.*;
37import javax.net.ssl.*;
38
39public class ReuseAddr {
40
41    /*
42     * =============================================================
43     * Set the various variables needed for the tests, then
44     * specify what tests to run on each side.
45     */
46
47    /*
48     * Should we run the client or server in a separate thread?
49     * Both sides can throw exceptions, but do you have a preference
50     * as to which side should be the main thread.
51     */
52    static boolean separateServerThread = true;
53
54    /*
55     * Where do we find the keystores?
56     */
57    private final static String pathToStores = "../../../../javax/net/ssl/etc";
58    static String keyStoreFile = "keystore";
59    static String trustStoreFile = "truststore";
60    static String passwd = "passphrase";
61
62    /*
63     * Is the server ready to serve?
64     */
65    volatile static boolean serverReady = false;
66
67    /*
68     * Turn on SSL debugging?
69     */
70    static boolean debug = false;
71
72    /*
73     * If the client or server is doing some kind of object creation
74     * that the other side depends on, and that thread prematurely
75     * exits, you may experience a hang.  The test harness will
76     * terminate all hung threads after its timeout has expired,
77     * currently 3 minutes by default, but you might try to be
78     * smart about it....
79     */
80
81    /*
82     * Define the server side of the test.
83     *
84     * If the server prematurely exits, serverReady will be set to true
85     * to avoid infinite hangs.
86     */
87    void doServerSide() throws Exception {
88        SSLServerSocketFactory sslssf =
89            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
90        SSLServerSocket sslServerSocket =
91            (SSLServerSocket) sslssf.createServerSocket(serverPort);
92        serverPort = sslServerSocket.getLocalPort();
93
94        /*
95         * Signal Client, we're ready for his connect.
96         */
97        serverReady = true;
98
99        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
100        InputStream sslIS = sslSocket.getInputStream();
101        OutputStream sslOS = sslSocket.getOutputStream();
102
103        sslIS.read();
104        sslOS.write(85);
105        sslOS.flush();
106
107        sslSocket.close();
108
109        // Close original server socket
110        sslServerSocket.close();
111
112        // Try rebinding to same port
113        sslServerSocket =
114            (SSLServerSocket) sslssf.createServerSocket(serverPort);
115        sslServerSocket.close();
116    }
117
118    /*
119     * Define the client side of the test.
120     *
121     * If the server prematurely exits, serverReady will be set to true
122     * to avoid infinite hangs.
123     */
124    void doClientSide() throws Exception {
125
126        /*
127         * Wait for server to get started.
128         */
129        while (!serverReady) {
130            Thread.sleep(50);
131        }
132
133        SSLSocketFactory sslsf =
134            (SSLSocketFactory) SSLSocketFactory.getDefault();
135        SSLSocket sslSocket = (SSLSocket)
136            sslsf.createSocket("localhost", serverPort);
137
138        InputStream sslIS = sslSocket.getInputStream();
139        OutputStream sslOS = sslSocket.getOutputStream();
140
141        sslOS.write(280);
142        sslOS.flush();
143        sslIS.read();
144
145        sslSocket.close();
146    }
147
148    /*
149     * =============================================================
150     * The remainder is just support stuff
151     */
152
153    // use any free port by default
154    volatile int serverPort = 0;
155
156    volatile Exception serverException = null;
157    volatile Exception clientException = null;
158
159    public static void main(String[] args) throws Exception {
160        String keyFilename =
161            System.getProperty("test.src", "./") + "/" + pathToStores +
162                "/" + keyStoreFile;
163        String trustFilename =
164            System.getProperty("test.src", "./") + "/" + pathToStores +
165                "/" + trustStoreFile;
166
167        System.setProperty("javax.net.ssl.keyStore", keyFilename);
168        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
169        System.setProperty("javax.net.ssl.trustStore", trustFilename);
170        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
171
172        if (debug)
173            System.setProperty("javax.net.debug", "all");
174
175        /*
176         * Start the tests.
177         */
178        new ReuseAddr();
179    }
180
181    Thread clientThread = null;
182    Thread serverThread = null;
183
184    /*
185     * Primary constructor, used to drive remainder of the test.
186     *
187     * Fork off the other side, then do your work.
188     */
189    ReuseAddr() throws Exception {
190        if (separateServerThread) {
191            startServer(true);
192            startClient(false);
193        } else {
194            startClient(true);
195            startServer(false);
196        }
197
198        /*
199         * Wait for other side to close down.
200         */
201        if (separateServerThread) {
202            serverThread.join();
203        } else {
204            clientThread.join();
205        }
206
207        /*
208         * When we get here, the test is pretty much over.
209         *
210         * If the main thread excepted, that propagates back
211         * immediately.  If the other thread threw an exception, we
212         * should report back.
213         */
214        if (serverException != null)
215            throw serverException;
216        if (clientException != null)
217            throw clientException;
218    }
219
220    void startServer(boolean newThread) throws Exception {
221        if (newThread) {
222            serverThread = new Thread() {
223                public void run() {
224                    try {
225                        doServerSide();
226                    } catch (Exception e) {
227                        /*
228                         * Our server thread just died.
229                         *
230                         * Release the client, if not active already...
231                         */
232                        System.err.println("Server died...");
233                        serverReady = true;
234                        serverException = e;
235                    }
236                }
237            };
238            serverThread.start();
239        } else {
240            doServerSide();
241        }
242   }
243
244    void startClient(boolean newThread) throws Exception {
245        if (newThread) {
246            clientThread = new Thread() {
247                public void run() {
248                    try {
249                        doClientSide();
250                    } catch (Exception e) {
251                        /*
252                         * Our client thread just died.
253                         */
254                        System.err.println("Client died...");
255                        clientException = e;
256                    }
257                }
258            };
259            clientThread.start();
260        } else {
261            doClientSide();
262        }
263    }
264}
265