2626
2727import java .io .IOException ;
2828import java .io .FileDescriptor ;
29+ import java .security .AccessController ;
30+ import java .security .PrivilegedAction ;
31+ import sun .security .action .GetPropertyAction ;
2932import jdk .internal .misc .SharedSecrets ;
3033import jdk .internal .misc .JavaIOFileDescriptorAccess ;
3134
3235/**
33- * This class defines the plain SocketImpl that is used on Windows platforms
34- * greater or equal to Windows Vista. These platforms have a dual
35- * layer TCP/IP stack and can handle both IPv4 and IPV6 through a
36- * single file descriptor.
36+ * This class defines the plain SocketImpl.
37+ * When java.net.preferIPv4Stack system property is set to true, it uses
38+ * IPv4-only socket.
39+ * When java.net.preferIPv4Stack is set to false, it handles both IPv4
40+ * and IPv6 through a single file descriptor.
3741 *
3842 * @author Chris Hegarty
3943 */
@@ -43,37 +47,53 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl {
4347 private static final JavaIOFileDescriptorAccess fdAccess =
4448 SharedSecrets .getJavaIOFileDescriptorAccess ();
4549
46- // true if this socket is exclusively bound
47- private final boolean exclusiveBind ;
50+ private static final boolean preferIPv4Stack =
51+ Boolean .parseBoolean (AccessController .doPrivileged (
52+ new GetPropertyAction ("java.net.preferIPv4Stack" , "false" )));
4853
49- // emulates SO_REUSEADDR when exclusiveBind is true
54+ /**
55+ * Empty value of sun.net.useExclusiveBind is treated as 'true'.
56+ */
57+ private static final boolean useExclusiveBind ;
58+
59+ static {
60+ String exclBindProp = AccessController .doPrivileged (
61+ new GetPropertyAction ("sun.net.useExclusiveBind" , "" ));
62+ useExclusiveBind = exclBindProp .isEmpty ()
63+ || Boolean .parseBoolean (exclBindProp );
64+ }
65+
66+ // emulates SO_REUSEADDR when useExclusiveBind is true
5067 private boolean isReuseAddress ;
5168
52- public DualStackPlainSocketImpl (boolean exclBind ) {
53- exclusiveBind = exclBind ;
69+ public DualStackPlainSocketImpl () {
5470 }
5571
56- public DualStackPlainSocketImpl (FileDescriptor fd , boolean exclBind ) {
72+ public DualStackPlainSocketImpl (FileDescriptor fd ) {
5773 this .fd = fd ;
58- exclusiveBind = exclBind ;
5974 }
6075
76+ @ Override
6177 void socketCreate (boolean stream ) throws IOException {
6278 if (fd == null )
6379 throw new SocketException ("Socket closed" );
6480
65- int newfd = socket0 (stream , false /*v6 Only*/ );
81+ int newfd = socket0 (stream );
6682
6783 fdAccess .set (fd , newfd );
6884 }
6985
86+ @ Override
7087 void socketConnect (InetAddress address , int port , int timeout )
7188 throws IOException {
7289 int nativefd = checkAndReturnNativeFD ();
7390
7491 if (address == null )
7592 throw new NullPointerException ("inet address argument is null." );
7693
94+ if (preferIPv4Stack && !(address instanceof Inet4Address ))
95+ throw new SocketException ("Protocol family not supported" );
96+
7797 int connectResult ;
7898 if (timeout <= 0 ) {
7999 connectResult = connect0 (nativefd , address , port );
@@ -97,13 +117,17 @@ void socketConnect(InetAddress address, int port, int timeout)
97117 localport = localPort0 (nativefd );
98118 }
99119
120+ @ Override
100121 void socketBind (InetAddress address , int port ) throws IOException {
101122 int nativefd = checkAndReturnNativeFD ();
102123
103124 if (address == null )
104125 throw new NullPointerException ("inet address argument is null." );
105126
106- bind0 (nativefd , address , port , exclusiveBind );
127+ if (preferIPv4Stack && !(address instanceof Inet4Address ))
128+ throw new SocketException ("Protocol family not supported" );
129+
130+ bind0 (nativefd , address , port , useExclusiveBind );
107131 if (port == 0 ) {
108132 localport = localPort0 (nativefd );
109133 } else {
@@ -113,12 +137,14 @@ void socketBind(InetAddress address, int port) throws IOException {
113137 this .address = address ;
114138 }
115139
140+ @ Override
116141 void socketListen (int backlog ) throws IOException {
117142 int nativefd = checkAndReturnNativeFD ();
118143
119144 listen0 (nativefd , backlog );
120145 }
121146
147+ @ Override
122148 void socketAccept (SocketImpl s ) throws IOException {
123149 int nativefd = checkAndReturnNativeFD ();
124150
@@ -148,13 +174,17 @@ void socketAccept(SocketImpl s) throws IOException {
148174 s .port = isa .getPort ();
149175 s .address = isa .getAddress ();
150176 s .localport = localport ;
177+ if (preferIPv4Stack && !(s .address instanceof Inet4Address ))
178+ throw new SocketException ("Protocol family not supported" );
151179 }
152180
181+ @ Override
153182 int socketAvailable () throws IOException {
154183 int nativefd = checkAndReturnNativeFD ();
155184 return available0 (nativefd );
156185 }
157186
187+ @ Override
158188 void socketClose0 (boolean useDeferredClose /*unused*/ ) throws IOException {
159189 if (fd == null )
160190 throw new SocketException ("Socket closed" );
@@ -167,48 +197,59 @@ void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
167197 close0 (nativefd );
168198 }
169199
200+ @ Override
170201 void socketShutdown (int howto ) throws IOException {
171202 int nativefd = checkAndReturnNativeFD ();
172203 shutdown0 (nativefd , howto );
173204 }
174205
175206 // Intentional fallthrough after SO_REUSEADDR
176207 @ SuppressWarnings ("fallthrough" )
208+ @ Override
177209 void socketSetOption (int opt , boolean on , Object value )
178210 throws SocketException {
179- int nativefd = checkAndReturnNativeFD ();
180211
181- if (opt == SO_TIMEOUT ) { // timeout implemented through select.
182- return ;
183- }
184212 // SO_REUSEPORT is not supported on Windows.
185213 if (opt == SO_REUSEPORT ) {
186214 throw new UnsupportedOperationException ("unsupported option" );
187215 }
188216
217+ int nativefd = checkAndReturnNativeFD ();
218+
219+ if (opt == SO_TIMEOUT ) {
220+ if (preferIPv4Stack ) {
221+ // Don't enable the socket option on ServerSocket as it's
222+ // meaningless (we don't receive on a ServerSocket).
223+ if (serverSocket == null ) {
224+ setSoTimeout0 (nativefd , ((Integer )value ).intValue ());
225+ }
226+ } // else timeout is implemented through select.
227+ return ;
228+ }
229+
189230 int optionValue = 0 ;
190231
191232 switch (opt ) {
192- case SO_REUSEADDR :
193- if (exclusiveBind ) {
233+ case SO_REUSEADDR :
234+ if (useExclusiveBind ) {
194235 // SO_REUSEADDR emulated when using exclusive bind
195236 isReuseAddress = on ;
196237 return ;
197238 }
198239 // intentional fallthrough
199- case TCP_NODELAY :
200- case SO_OOBINLINE :
201- case SO_KEEPALIVE :
240+ case TCP_NODELAY :
241+ case SO_OOBINLINE :
242+ case SO_KEEPALIVE :
202243 optionValue = on ? 1 : 0 ;
203244 break ;
204- case SO_SNDBUF :
205- case SO_RCVBUF :
206- case IP_TOS :
245+ case SO_SNDBUF :
246+ case SO_RCVBUF :
247+ case IP_TOS :
207248 optionValue = ((Integer )value ).intValue ();
208249 break ;
209- case SO_LINGER :
250+ case SO_LINGER :
210251 if (on ) {
211- optionValue = ((Integer )value ).intValue ();
252+ optionValue = ((Integer )value ).intValue ();
212253 } else {
213254 optionValue = -1 ;
214255 }
@@ -220,35 +261,40 @@ void socketSetOption(int opt, boolean on, Object value)
220261 setIntOption (nativefd , opt , optionValue );
221262 }
222263
223- int socketGetOption (int opt , Object iaContainerObj ) throws SocketException {
264+ @ Override
265+ int socketGetOption (int opt , Object iaContainerObj )
266+ throws SocketException {
267+
268+ // SO_REUSEPORT is not supported on Windows.
269+ if (opt == SO_REUSEPORT ) {
270+ throw new UnsupportedOperationException ("unsupported option" );
271+ }
272+
224273 int nativefd = checkAndReturnNativeFD ();
225274
226275 // SO_BINDADDR is not a socket option.
227276 if (opt == SO_BINDADDR ) {
228277 localAddress (nativefd , (InetAddressContainer )iaContainerObj );
229278 return 0 ; // return value doesn't matter.
230279 }
231- // SO_REUSEPORT is not supported on Windows.
232- if (opt == SO_REUSEPORT ) {
233- throw new UnsupportedOperationException ("unsupported option" );
234- }
235280
236281 // SO_REUSEADDR emulated when using exclusive bind
237- if (opt == SO_REUSEADDR && exclusiveBind )
238- return isReuseAddress ? 1 : -1 ;
282+ if (opt == SO_REUSEADDR && useExclusiveBind )
283+ return isReuseAddress ? 1 : -1 ;
239284
240285 int value = getIntOption (nativefd , opt );
241286
242287 switch (opt ) {
243- case TCP_NODELAY :
244- case SO_OOBINLINE :
245- case SO_KEEPALIVE :
246- case SO_REUSEADDR :
288+ case TCP_NODELAY :
289+ case SO_OOBINLINE :
290+ case SO_KEEPALIVE :
291+ case SO_REUSEADDR :
247292 return (value == 0 ) ? -1 : 1 ;
248293 }
249294 return value ;
250295 }
251296
297+ @ Override
252298 void socketSendUrgentData (int data ) throws IOException {
253299 int nativefd = checkAndReturnNativeFD ();
254300 sendOOB (nativefd , data );
@@ -271,7 +317,7 @@ private int checkAndReturnNativeFD() throws SocketException {
271317
272318 static native void initIDs ();
273319
274- static native int socket0 (boolean stream , boolean v6Only ) throws IOException ;
320+ static native int socket0 (boolean stream ) throws IOException ;
275321
276322 static native void bind0 (int fd , InetAddress localAddress , int localport ,
277323 boolean exclBind )
@@ -300,6 +346,8 @@ static native int connect0(int fd, InetAddress remote, int remotePort)
300346
301347 static native void setIntOption (int fd , int cmd , int optionValue ) throws SocketException ;
302348
349+ static native void setSoTimeout0 (int fd , int timeout ) throws SocketException ;
350+
303351 static native int getIntOption (int fd , int cmd ) throws SocketException ;
304352
305353 static native void sendOOB (int fd , int data ) throws IOException ;
0 commit comments