1 /*
2  * Copyright (c) 2007, 2019, 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 4640544 8044773
26  * @summary Unit test to check SocketChannel setOption/getOption/options
27  *          methods.
28  * @modules java.base/sun.net.ext
29  *          jdk.net
30  * @requires !vm.graal.enabled
31  * @run main SocketOptionTests
32  * @run main/othervm --limit-modules=java.base SocketOptionTests
33  */
34 
35 import java.io.IOException;
36 import java.net.InetSocketAddress;
37 import java.net.SocketOption;
38 import java.nio.channels.ClosedChannelException;
39 import java.nio.channels.SocketChannel;
40 import java.util.Set;
41 import sun.net.ext.ExtendedSocketOptions;
42 import static java.net.StandardSocketOptions.*;
43 import static jdk.net.ExtendedSocketOptions.*;
44 
45 public class SocketOptionTests {
46 
checkOption(SocketChannel sc, SocketOption name, Object expectedValue)47     static void checkOption(SocketChannel sc, SocketOption name, Object expectedValue)
48         throws IOException
49     {
50         Object value = sc.getOption(name);
51         if (!value.equals(expectedValue))
52             throw new RuntimeException("value not as expected");
53     }
54 
main(String[] args)55     public static void main(String[] args) throws IOException {
56         try (var channel = SocketChannel.open()) {
57             test(channel);
58         }
59     }
60 
test(SocketChannel sc)61     static void test(SocketChannel sc) throws IOException {
62         Set<SocketOption<?>> extendedOptions = ExtendedSocketOptions.clientSocketOptions();
63         Set<SocketOption<?>> keepAliveOptions = Set.of(TCP_KEEPCOUNT, TCP_KEEPIDLE, TCP_KEEPINTERVAL);
64         boolean keepAliveOptionsSupported = extendedOptions.containsAll(keepAliveOptions);
65         Set<SocketOption<?>> expected;
66         if (keepAliveOptionsSupported) {
67             expected = Set.of(SO_SNDBUF, SO_RCVBUF, SO_KEEPALIVE,
68                     SO_REUSEADDR, SO_LINGER, TCP_NODELAY, TCP_KEEPCOUNT,
69                     TCP_KEEPIDLE, TCP_KEEPINTERVAL);
70         } else {
71             expected = Set.of(SO_SNDBUF, SO_RCVBUF, SO_KEEPALIVE,
72                     SO_REUSEADDR, SO_LINGER, TCP_NODELAY);
73         }
74         for (SocketOption opt: expected) {
75             if (!sc.supportedOptions().contains(opt))
76                 throw new RuntimeException(opt.name() + " should be supported");
77         }
78 
79         // check specified defaults
80         int linger = sc.<Integer>getOption(SO_LINGER);
81         if (linger >= 0)
82             throw new RuntimeException("initial value of SO_LINGER should be < 0");
83         checkOption(sc, SO_KEEPALIVE, false);
84         checkOption(sc, TCP_NODELAY, false);
85 
86         // allowed to change when not bound
87         sc.setOption(SO_KEEPALIVE, true);
88         checkOption(sc, SO_KEEPALIVE, true);
89         sc.setOption(SO_KEEPALIVE, false);
90         checkOption(sc, SO_KEEPALIVE, false);
91         sc.setOption(SO_SNDBUF, 128*1024);      // can't check
92         sc.setOption(SO_RCVBUF, 256*1024);      // can't check
93         int before, after;
94         before = sc.getOption(SO_SNDBUF);
95         after = sc.setOption(SO_SNDBUF, Integer.MAX_VALUE).getOption(SO_SNDBUF);
96         if (after < before)
97             throw new RuntimeException("setOption caused SO_SNDBUF to decrease");
98         before = sc.getOption(SO_RCVBUF);
99         after = sc.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
100         if (after < before)
101             throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
102         sc.setOption(SO_REUSEADDR, true);
103         checkOption(sc, SO_REUSEADDR, true);
104         sc.setOption(SO_REUSEADDR, false);
105         checkOption(sc, SO_REUSEADDR, false);
106         sc.setOption(SO_LINGER, 10);
107         linger = sc.<Integer>getOption(SO_LINGER);
108         if (linger < 1)
109             throw new RuntimeException("expected linger to be enabled");
110         sc.setOption(SO_LINGER, -1);
111         linger = sc.<Integer>getOption(SO_LINGER);
112         if (linger >= 0)
113             throw new RuntimeException("expected linger to be disabled");
114         sc.setOption(TCP_NODELAY, true);
115         checkOption(sc, TCP_NODELAY, true);
116         sc.setOption(TCP_NODELAY, false);       // can't check
117 
118         // bind socket
119         sc.bind(new InetSocketAddress(0));
120 
121         // allow to change when bound
122         sc.setOption(SO_KEEPALIVE, true);
123         checkOption(sc, SO_KEEPALIVE, true);
124         sc.setOption(SO_KEEPALIVE, false);
125         checkOption(sc, SO_KEEPALIVE, false);
126 
127         sc.setOption(SO_LINGER, 10);
128         linger = sc.<Integer>getOption(SO_LINGER);
129         if (linger < 1)
130             throw new RuntimeException("expected linger to be enabled");
131         sc.setOption(SO_LINGER, -1);
132         linger = sc.<Integer>getOption(SO_LINGER);
133         if (linger >= 0)
134             throw new RuntimeException("expected linger to be disabled");
135         sc.setOption(TCP_NODELAY, true);        // can't check
136         sc.setOption(TCP_NODELAY, false);       // can't check
137         if (keepAliveOptionsSupported) {
138             sc.setOption(TCP_KEEPIDLE, 1234);
139             checkOption(sc, TCP_KEEPIDLE, 1234);
140             sc.setOption(TCP_KEEPINTERVAL, 123);
141             checkOption(sc, TCP_KEEPINTERVAL, 123);
142             sc.setOption(TCP_KEEPCOUNT, 7);
143             checkOption(sc, TCP_KEEPCOUNT, 7);
144         }
145         // NullPointerException
146         try {
147             sc.setOption(null, "value");
148             throw new RuntimeException("NullPointerException not thrown");
149         } catch (NullPointerException x) {
150         }
151         try {
152             sc.getOption(null);
153             throw new RuntimeException("NullPointerException not thrown");
154         } catch (NullPointerException x) {
155         }
156 
157         // ClosedChannelException
158         sc.close();
159         try {
160             sc.setOption(TCP_NODELAY, true);
161             throw new RuntimeException("ClosedChannelException not thrown");
162         } catch (ClosedChannelException x) {
163         }
164     }
165 }