1 /*
2 * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 *
5 *
6 *
7 *
8 *
9 *
10 *
11 *
12 *
13 *
14 *
15 *
16 *
17 *
18 *
19 *
20 *
21 *
22 *
23 *
24 */
25 package java.net;
26
27 import java.io.IOException;
28 import java.io.FileDescriptor;
29 import sun.net.ResourceManager;
30
31 /*
32 * This class defines the plain SocketImpl that is used for all
33 * Windows version lower than Vista. It adds support for IPv6 on
34 * these platforms where available.
35 *
36 * For backward compatibility Windows platforms that do not have IPv6
37 * support also use this implementation, and fd1 gets set to null
38 * during socket creation.
39 *
40 * @author Chris Hegarty
41 */
42
43 class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl
44 {
45 /* second fd, used for ipv6 on windows only.
46 * fd1 is used for listeners and for client sockets at initialization
47 * until the socket is connected. Up to this point fd always refers
48 * to the ipv4 socket and fd1 to the ipv6 socket. After the socket
49 * becomes connected, fd always refers to the connected socket
50 * (either v4 or v6) and fd1 is closed.
51 *
52 * For ServerSockets, fd always refers to the v4 listener and
53 * fd1 the v6 listener.
54 */
55 private FileDescriptor fd1;
56
57 /*
58 * Needed for ipv6 on windows because we need to know
59 * if the socket is bound to ::0 or 0.0.0.0, when a caller
60 * asks for it. Otherwise we don't know which socket to ask.
61 */
62 private InetAddress anyLocalBoundAddr = null;
63
64 /* to prevent starvation when listening on two sockets, this is
65 * is used to hold the id of the last socket we accepted on.
66 */
67 private int lastfd = -1;
68
69 // true if this socket is exclusively bound
70 private final boolean exclusiveBind;
71
72 // emulates SO_REUSEADDR when exclusiveBind is true
73 private boolean isReuseAddress;
74
75 static {
76 initProto();
77 }
78
79 public TwoStacksPlainSocketImpl(boolean exclBind) {
80 exclusiveBind = exclBind;
81 }
82
83 public TwoStacksPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
84 this.fd = fd;
85 exclusiveBind = exclBind;
86 }
87
88 /**
89 * Creates a socket with a boolean that specifies whether this
90 * is a stream socket (true) or an unconnected UDP socket (false).
91 */
92 protected synchronized void create(boolean stream) throws IOException {
93 fd1 = new FileDescriptor();
94 try {
95 super.create(stream);
96 } catch (IOException e) {
97 fd1 = null;
98 throw e;
99 }
100 }
101
102 /**
103 * Binds the socket to the specified address of the specified local port.
104 * @param address the address
105 * @param port the port
106 */
107 protected synchronized void bind(InetAddress address, int lport)
108 throws IOException
109 {
110 super.bind(address, lport);
111 if (address.isAnyLocalAddress()) {
112 anyLocalBoundAddr = address;
113 }
114 }
115
116 public Object getOption(int opt) throws SocketException {
117 if (isClosedOrPending()) {
118 throw new SocketException("Socket Closed");
119 }
120 if (opt == SO_BINDADDR) {
121 if (fd != null && fd1 != null ) {
122 /* must be unbound or else bound to anyLocal */
123 return anyLocalBoundAddr;
124 }
125 InetAddressContainer in = new InetAddressContainer();
126 socketGetOption(opt, in);
127 return in.addr;
128 } else if (opt == SO_REUSEADDR && exclusiveBind) {
129 // SO_REUSEADDR emulated when using exclusive bind
130 return isReuseAddress;
131 } else
132 return super.getOption(opt);
133 }
134
135 @Override
136 void socketBind(InetAddress address, int port) throws IOException {
137 socketBind(address, port, exclusiveBind);
138 }
139
140 @Override
141 void socketSetOption(int opt, boolean on, Object value)
142 throws SocketException
143 {
144 // SO_REUSEADDR emulated when using exclusive bind
145 if (opt == SO_REUSEADDR && exclusiveBind)
146 isReuseAddress = on;
147 else
148 socketNativeSetOption(opt, on, value);
149 }
150
151 /**
152 * Closes the socket.
153 */
154 @Override
155 protected void close() throws IOException {
156 synchronized(fdLock) {
157 if (fd != null || fd1 != null) {
158 if (!stream) {
159 ResourceManager.afterUdpClose();
160 }
161 if (fdUseCount == 0) {
162 if (closePending) {
163 return;
164 }
165 closePending = true;
166 socketClose();
167 fd = null;
168 fd1 = null;
169 return;
170 } else {
171 /*
172 * If a thread has acquired the fd and a close
173 * isn't pending then use a deferred close.
174 * Also decrement fdUseCount to signal the last
175 * thread that releases the fd to close it.
176 */
177 if (!closePending) {
178 closePending = true;
179 fdUseCount--;
180 socketClose();
181 }
182 }
183 }
184 }
185 }
186
187 @Override
188 void reset() throws IOException {
189 if (fd != null || fd1 != null) {
190 socketClose();
191 }
192 fd = null;
193 fd1 = null;
194 super.reset();
195 }
196
197 /*
198 * Return true if already closed or close is pending
199 */
200 @Override
201 public boolean isClosedOrPending() {
202 /*
203 * Lock on fdLock to ensure that we wait if a
204 * close is in progress.
205 */
206 synchronized (fdLock) {
207 if (closePending || (fd == null && fd1 == null)) {
208 return true;
209 } else {
210 return false;
211 }
212 }
213 }
214
215 /* Native methods */
216
217 static native void initProto();
218
219 native void socketCreate(boolean isServer) throws IOException;
220
221 native void socketConnect(InetAddress address, int port, int timeout)
222 throws IOException;
223
224 native void socketBind(InetAddress address, int port, boolean exclBind)
225 throws IOException;
226
227 native void socketListen(int count) throws IOException;
228
229 native void socketAccept(SocketImpl s) throws IOException;
230
231 native int socketAvailable() throws IOException;
232
233 native void socketClose0(boolean useDeferredClose) throws IOException;
234
235 native void socketShutdown(int howto) throws IOException;
236
237 native void socketNativeSetOption(int cmd, boolean on, Object value)
238 throws SocketException;
239
240 native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
241
242 native void socketSendUrgentData(int data) throws IOException;
243 }
244