1 /*
2  * Copyright (c) 2002, 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 /* @test
25  * @bug 4617165
26  * @summary Ensure that socket hangups are handled correctly
27  * @library ..
28  * @build TestUtil
29  * @run main Hangup
30  */
31 
32 import java.io.*;
33 import java.net.*;
34 import java.nio.*;
35 import java.nio.channels.*;
36 import java.util.*;
37 
38 
39 public class Hangup {
40 
41     static PrintStream log = System.err;
42     static int failures = 0;
43 
44     private static class Failure
45         extends RuntimeException
46     {
47 
Failure(String s)48         Failure(String s) {
49             super(s);
50         }
51 
52     }
53 
doSelect(Selector sel, SelectionKey sk, int count)54     static void doSelect(Selector sel, SelectionKey sk, int count)
55         throws IOException
56     {
57         int n = sel.select();
58         if (n != 1)
59             throw new Failure("Select returned zero");
60         Set sks = sel.selectedKeys();
61         if (sks.size() != 1)
62             throw new Failure("Wrong size for selected-key set: "
63                               + sks.size());
64         if (!sks.remove(sk))
65             throw new Failure("Key not in selected-key set");
66         log.println("S: Socket selected #" + count);
67     }
68 
dally()69     static void dally() {
70         try {
71             Thread.sleep(100);
72         } catch (InterruptedException x) { }
73     }
74 
test(boolean writeFromClient, boolean readAfterClose)75     static void test(boolean writeFromClient, boolean readAfterClose)
76         throws IOException
77     {
78 
79         ServerSocketChannel ssc = null;
80         SocketChannel cl = null;        // client end
81         SocketChannel sv = null;        // server end
82         Selector sel = null;
83 
84         log.println();
85         log.println("Test: writeFromClient = " + writeFromClient
86                     + ", readAfterClose = " + readAfterClose);
87 
88         try {
89 
90             int ns = 0;                 // Number of selection operations done
91 
92             // Set up server socket
93             ssc = ServerSocketChannel.open();
94             SocketAddress sa = TestUtil.bindToRandomPort(ssc);
95             log.println("S: Listening on port "
96                         + ssc.socket().getLocalPort());
97 
98             // Connect client
99             cl = SocketChannel.open(sa);
100             log.println("C: Connected via port "
101                         + cl.socket().getLocalPort());
102 
103             // Accept client connection
104             sv = ssc.accept();
105             log.println("S: Client connection accepted");
106 
107             // Create selector and register server side
108             sel = Selector.open();
109             sv.configureBlocking(false);
110             SelectionKey sk = sv.register(sel, SelectionKey.OP_READ);
111 
112             ByteBuffer stuff = ByteBuffer.allocate(10);
113             int n;
114 
115             if (writeFromClient) {
116 
117                 // Write from client, read from server
118 
119                 stuff.clear();
120                 if (cl.write(stuff) != stuff.capacity())
121                     throw new Failure("Incorrect number of bytes written");
122                 log.println("C: Wrote stuff");
123                 dally();
124 
125                 doSelect(sel, sk, ++ns);
126 
127                 stuff.clear();
128                 if (sv.read(stuff) != stuff.capacity())
129                     throw new Failure("Wrong number of bytes read");
130                 log.println("S: Read stuff");
131             }
132 
133             // Close client side
134             cl.close();
135             log.println("C: Socket closed");
136             dally();
137 
138             // Select again
139             doSelect(sel, sk, ++ns);
140 
141             if (readAfterClose) {
142                 // Read from client after client has disconnected
143                 stuff.clear();
144                 if (sv.read(stuff) != -1)
145                     throw new Failure("Wrong number of bytes read");
146                 log.println("S: Read EOF");
147             }
148 
149             // Select a couple more times just to make sure we're doing
150             // the right thing
151 
152             doSelect(sel, sk, ++ns);
153             doSelect(sel, sk, ++ns);
154 
155         } finally {
156             if (ssc != null)
157                 ssc.close();
158             if (cl != null)
159                 cl.close();
160             if (sv != null)
161                 sv.close();
162             if (sel != null)
163                 sel.close();
164         }
165 
166     }
167 
main(String[] args)168     public static void main(String[] args) throws IOException {
169 
170         for (boolean writeFromClient = false;; writeFromClient = true) {
171             for (boolean readAfterClose = false;; readAfterClose = true) {
172                 try {
173                     test(writeFromClient, readAfterClose);
174                 } catch (Failure x) {
175                     x.printStackTrace(log);
176                     failures++;
177                 }
178                 if (readAfterClose)
179                     break;
180             }
181             if (writeFromClient)
182                 break;
183         }
184 
185         if (failures > 0) {
186             log.println();
187             throw new RuntimeException("Some tests failed");
188         }
189 
190     }
191 
192 }
193