1/*
2 * Copyright (c) 2003, 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 4814140
27 * @summary AppInputStream: read can block a close
28 * @run main/othervm ReadBlocksClose
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 ReadBlocksClose {
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 = false;
53
54    /*
55     * Where do we find the keystores?
56     */
57    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
93        serverPort = sslServerSocket.getLocalPort();
94
95        /*
96         * Signal Client, we're ready for his connect.
97         */
98        serverReady = true;
99
100        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
101        InputStream sslIS = sslSocket.getInputStream();
102        OutputStream sslOS = sslSocket.getOutputStream();
103
104        try {
105            sslIS.read();
106        } catch (IOException e) {
107            // this is ok, we expect this to time out anyway if the bug
108            // is not fixed.  This is just to make sure that we
109            // don't inadvertantly fail.
110        }
111
112        sslSocket.close();
113    }
114
115    /*
116     * Define the client side of the test.
117     *
118     * If the server prematurely exits, serverReady will be set to true
119     * to avoid infinite hangs.
120     */
121    void doClientSide() throws Exception {
122
123        /*
124         * Wait for server to get started.
125         */
126        while (!serverReady) {
127            Thread.sleep(50);
128        }
129
130        SSLSocketFactory sslsf =
131            (SSLSocketFactory) SSLSocketFactory.getDefault();
132        SSLSocket sslSocket = (SSLSocket)
133            sslsf.createSocket("localhost", serverPort);
134
135        final InputStream sslIS = sslSocket.getInputStream();
136        final OutputStream sslOS = sslSocket.getOutputStream();
137
138        new Thread(new Runnable() {
139            public void run() {
140                try {
141                    System.out.println("Closing Thread started");
142                    Thread.sleep(3000);
143                    System.out.println("Closing Thread closing");
144                    sslIS.close();
145                } catch (Exception e) {
146                    RuntimeException rte =
147                        new RuntimeException("Check this out");
148                    rte.initCause(e);
149                    throw rte;
150                }
151            }
152        }).start();
153
154        try {
155            /*
156             * This should timeout and fail the test
157             */
158            System.out.println("Client starting read");
159            sslIS.read();
160        } catch (IOException e) {
161            // this is ok, we expect this to time out anyway if the bug
162            // is not fixed.  This is just to make sure that we
163            // don't inadvertantly fail.
164        }
165
166        sslSocket.close();
167    }
168
169    /*
170     * =============================================================
171     * The remainder is just support stuff
172     */
173
174    // use any free port by default
175    volatile int serverPort = 0;
176
177    volatile Exception serverException = null;
178    volatile Exception clientException = null;
179
180    public static void main(String[] args) throws Exception {
181        String keyFilename =
182            System.getProperty("test.src", "./") + "/" + pathToStores +
183                "/" + keyStoreFile;
184        String trustFilename =
185            System.getProperty("test.src", "./") + "/" + pathToStores +
186                "/" + trustStoreFile;
187
188        System.setProperty("javax.net.ssl.keyStore", keyFilename);
189        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
190        System.setProperty("javax.net.ssl.trustStore", trustFilename);
191        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
192
193        if (debug)
194            System.setProperty("javax.net.debug", "all");
195
196        /*
197         * Start the tests.
198         */
199        new ReadBlocksClose();
200    }
201
202    Thread clientThread = null;
203    Thread serverThread = null;
204
205    /*
206     * Primary constructor, used to drive remainder of the test.
207     *
208     * Fork off the other side, then do your work.
209     */
210    ReadBlocksClose() throws Exception {
211        try {
212            if (separateServerThread) {
213                startServer(true);
214                startClient(false);
215            } else {
216                startClient(true);
217                startServer(false);
218            }
219        } catch (Exception e) {
220            // swallow for now.  Show later
221        }
222
223        /*
224         * Wait for other side to close down.
225         */
226        if (separateServerThread) {
227            serverThread.join();
228        } else {
229            clientThread.join();
230        }
231
232        /*
233         * When we get here, the test is pretty much over.
234         * Which side threw the error?
235         */
236        Exception local;
237        Exception remote;
238        String whichRemote;
239
240        if (separateServerThread) {
241            remote = serverException;
242            local = clientException;
243            whichRemote = "server";
244        } else {
245            remote = clientException;
246            local = serverException;
247            whichRemote = "client";
248        }
249
250        /*
251         * If both failed, return the curthread's exception, but also
252         * print the remote side Exception
253         */
254        if ((local != null) && (remote != null)) {
255            System.out.println(whichRemote + " also threw:");
256            remote.printStackTrace();
257            System.out.println();
258            throw local;
259        }
260
261        if (remote != null) {
262            throw remote;
263        }
264
265        if (local != null) {
266            throw local;
267        }
268    }
269
270    void startServer(boolean newThread) throws Exception {
271        if (newThread) {
272            serverThread = new Thread() {
273                public void run() {
274                    try {
275                        doServerSide();
276                    } catch (Exception e) {
277                        /*
278                         * Our server thread just died.
279                         *
280                         * Release the client, if not active already...
281                         */
282                        System.err.println("Server died...");
283                        serverReady = true;
284                        serverException = e;
285                    }
286                }
287            };
288            serverThread.start();
289        } else {
290            try {
291                doServerSide();
292            } catch (Exception e) {
293                serverException = e;
294            } finally {
295                serverReady = true;
296            }
297        }
298    }
299
300    void startClient(boolean newThread) throws Exception {
301        if (newThread) {
302            clientThread = new Thread() {
303                public void run() {
304                    try {
305                        doClientSide();
306                    } catch (Exception e) {
307                        /*
308                         * Our client thread just died.
309                         */
310                        System.err.println("Client died...");
311                        clientException = e;
312                    }
313                }
314            };
315            clientThread.start();
316        } else {
317            try {
318                doClientSide();
319            } catch (Exception e) {
320                clientException = e;
321            }
322        }
323    }
324}
325