Skip to content

Commit 9303a8a

Browse files
author
Ivan Gerasimov
committed
8201510: Merge TwoStacksPlainSocketImpl into DualStackPlainSocketImpl [win]
Reviewed-by: chegar
1 parent e81b41a commit 9303a8a

8 files changed

Lines changed: 253 additions & 993 deletions

File tree

src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java

Lines changed: 87 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,18 @@
2626

2727
import java.io.IOException;
2828
import java.io.FileDescriptor;
29+
import java.security.AccessController;
30+
import java.security.PrivilegedAction;
31+
import sun.security.action.GetPropertyAction;
2932
import jdk.internal.misc.SharedSecrets;
3033
import 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;

src/java.base/windows/classes/java/net/PlainSocketImpl.java

Lines changed: 5 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -25,65 +25,32 @@
2525
package java.net;
2626

2727
import java.io.*;
28-
import java.security.AccessController;
29-
import java.security.PrivilegedAction;
30-
import sun.security.action.GetPropertyAction;
3128

3229
/*
3330
* This class PlainSocketImpl simply delegates to the appropriate real
3431
* SocketImpl. We do this because PlainSocketImpl is already extended
3532
* by SocksSocketImpl.
3633
* <p>
37-
* There are two possibilities for the real SocketImpl,
38-
* TwoStacksPlainSocketImpl or DualStackPlainSocketImpl. We use
39-
* DualStackPlainSocketImpl on systems that have a dual stack
40-
* TCP implementation. Otherwise we create an instance of
41-
* TwoStacksPlainSocketImpl and delegate to it.
34+
* There is one possibility for the real SocketImpl: DualStackPlainSocketImpl.
4235
*
4336
* @author Chris Hegarty
4437
*/
4538

4639
class PlainSocketImpl extends AbstractPlainSocketImpl {
4740
private AbstractPlainSocketImpl impl;
4841

49-
/* java.net.preferIPv4Stack */
50-
private static final boolean preferIPv4Stack;
51-
52-
/* True if exclusive binding is on for Windows */
53-
private static final boolean exclusiveBind;
54-
55-
static {
56-
preferIPv4Stack = Boolean.parseBoolean(
57-
AccessController.doPrivileged(
58-
new GetPropertyAction("java.net.preferIPv4Stack")));
59-
60-
String exclBindProp = AccessController.doPrivileged(
61-
new GetPropertyAction("sun.net.useExclusiveBind", ""));
62-
exclusiveBind = (exclBindProp.isEmpty())
63-
? true
64-
: Boolean.parseBoolean(exclBindProp);
65-
}
66-
6742
/**
6843
* Constructs an empty instance.
6944
*/
7045
PlainSocketImpl() {
71-
if (!preferIPv4Stack) {
72-
impl = new DualStackPlainSocketImpl(exclusiveBind);
73-
} else {
74-
impl = new TwoStacksPlainSocketImpl(exclusiveBind);
75-
}
46+
impl = new DualStackPlainSocketImpl();
7647
}
7748

7849
/**
7950
* Constructs an instance with the given file descriptor.
8051
*/
8152
PlainSocketImpl(FileDescriptor fd) {
82-
if (!preferIPv4Stack) {
83-
impl = new DualStackPlainSocketImpl(fd, exclusiveBind);
84-
} else {
85-
impl = new TwoStacksPlainSocketImpl(fd, exclusiveBind);
86-
}
53+
impl = new DualStackPlainSocketImpl(fd);
8754
}
8855

8956
// Override methods in SocketImpl that access impl's fields.
@@ -148,18 +115,10 @@ protected void connect(SocketAddress address, int timeout) throws IOException {
148115
}
149116

150117
public void setOption(int opt, Object val) throws SocketException {
151-
if (opt == SocketOptions.SO_REUSEPORT) {
152-
// SO_REUSEPORT is not supported on Windows.
153-
throw new UnsupportedOperationException("unsupported option");
154-
}
155118
impl.setOption(opt, val);
156119
}
157120

158121
public Object getOption(int opt) throws SocketException {
159-
if (opt == SocketOptions.SO_REUSEPORT) {
160-
// SO_REUSEPORT is not supported on Windows.
161-
throw new UnsupportedOperationException("unsupported option");
162-
}
163122
return impl.getOption(opt);
164123
}
165124

@@ -271,8 +230,8 @@ public int getTimeout() {
271230

272231
// Override methods in AbstractPlainSocketImpl that need to be implemented.
273232

274-
void socketCreate(boolean isServer) throws IOException {
275-
impl.socketCreate(isServer);
233+
void socketCreate(boolean stream) throws IOException {
234+
impl.socketCreate(stream);
276235
}
277236

278237
void socketConnect(InetAddress address, int port, int timeout)
@@ -307,18 +266,10 @@ void socketShutdown(int howto) throws IOException {
307266

308267
void socketSetOption(int cmd, boolean on, Object value)
309268
throws SocketException {
310-
if (cmd == SocketOptions.SO_REUSEPORT) {
311-
// SO_REUSEPORT is not supported on Windows.
312-
throw new UnsupportedOperationException("unsupported option");
313-
}
314269
impl.socketSetOption(cmd, on, value);
315270
}
316271

317272
int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
318-
if (opt == SocketOptions.SO_REUSEPORT) {
319-
// SO_REUSEPORT is not supported on Windows.
320-
throw new UnsupportedOperationException("unsupported option");
321-
}
322273
return impl.socketGetOption(opt, iaContainerObj);
323274
}
324275

0 commit comments

Comments
 (0)