1 /*
2  * Copyright (c) 2007, 2013, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package java.net;
26 
27 import java.io.IOException;
28 import java.io.FileDescriptor;
29 import sun.misc.SharedSecrets;
30 import sun.misc.JavaIOFileDescriptorAccess;
31 
32 /**
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.
37  *
38  * @author Chris Hegarty
39  */
40 
41 class DualStackPlainSocketImpl extends AbstractPlainSocketImpl
42 {
43     static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
44 
45 
46     // true if this socket is exclusively bound
47     private final boolean exclusiveBind;
48 
49     // emulates SO_REUSEADDR when exclusiveBind is true
50     private boolean isReuseAddress;
51 
DualStackPlainSocketImpl(boolean exclBind)52     public DualStackPlainSocketImpl(boolean exclBind) {
53         exclusiveBind = exclBind;
54     }
55 
DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind)56     public DualStackPlainSocketImpl(FileDescriptor fd, boolean exclBind) {
57         this.fd = fd;
58         exclusiveBind = exclBind;
59     }
60 
socketCreate(boolean stream)61     void socketCreate(boolean stream) throws IOException {
62         if (fd == null)
63             throw new SocketException("Socket closed");
64 
65         int newfd = socket0(stream, false /*v6 Only*/);
66 
67         fdAccess.set(fd, newfd);
68     }
69 
socketConnect(InetAddress address, int port, int timeout)70     void socketConnect(InetAddress address, int port, int timeout)
71         throws IOException {
72         int nativefd = checkAndReturnNativeFD();
73 
74         if (address == null)
75             throw new NullPointerException("inet address argument is null.");
76 
77         int connectResult;
78         if (timeout <= 0) {
79             connectResult = connect0(nativefd, address, port);
80         } else {
81             configureBlocking(nativefd, false);
82             try {
83                 connectResult = connect0(nativefd, address, port);
84                 if (connectResult == WOULDBLOCK) {
85                     waitForConnect(nativefd, timeout);
86                 }
87             } finally {
88                 configureBlocking(nativefd, true);
89             }
90         }
91         /*
92          * We need to set the local port field. If bind was called
93          * previous to the connect (by the client) then localport field
94          * will already be set.
95          */
96         if (localport == 0)
97             localport = localPort0(nativefd);
98     }
99 
socketBind(InetAddress address, int port)100     void socketBind(InetAddress address, int port) throws IOException {
101         int nativefd = checkAndReturnNativeFD();
102 
103         if (address == null)
104             throw new NullPointerException("inet address argument is null.");
105 
106         bind0(nativefd, address, port, exclusiveBind);
107         if (port == 0) {
108             localport = localPort0(nativefd);
109         } else {
110             localport = port;
111         }
112 
113         this.address = address;
114     }
115 
socketListen(int backlog)116     void socketListen(int backlog) throws IOException {
117         int nativefd = checkAndReturnNativeFD();
118 
119         listen0(nativefd, backlog);
120     }
121 
socketAccept(SocketImpl s)122     void socketAccept(SocketImpl s) throws IOException {
123         int nativefd = checkAndReturnNativeFD();
124 
125         if (s == null)
126             throw new NullPointerException("socket is null");
127 
128         int newfd = -1;
129         InetSocketAddress[] isaa = new InetSocketAddress[1];
130         if (timeout <= 0) {
131             newfd = accept0(nativefd, isaa);
132         } else {
133             configureBlocking(nativefd, false);
134             try {
135                 waitForNewConnection(nativefd, timeout);
136                 newfd = accept0(nativefd, isaa);
137                 if (newfd != -1) {
138                     configureBlocking(newfd, true);
139                 }
140             } finally {
141                 configureBlocking(nativefd, true);
142             }
143         }
144         /* Update (SocketImpl)s' fd */
145         fdAccess.set(s.fd, newfd);
146         /* Update socketImpls remote port, address and localport */
147         InetSocketAddress isa = isaa[0];
148         s.port = isa.getPort();
149         s.address = isa.getAddress();
150         s.localport = localport;
151     }
152 
socketAvailable()153     int socketAvailable() throws IOException {
154         int nativefd = checkAndReturnNativeFD();
155         return available0(nativefd);
156     }
157 
socketClose0(boolean useDeferredClose )158     void socketClose0(boolean useDeferredClose/*unused*/) throws IOException {
159         if (fd == null)
160             throw new SocketException("Socket closed");
161 
162         if (!fd.valid())
163             return;
164 
165         final int nativefd = fdAccess.get(fd);
166         fdAccess.set(fd, -1);
167         close0(nativefd);
168     }
169 
socketShutdown(int howto)170     void socketShutdown(int howto) throws IOException {
171         int nativefd = checkAndReturnNativeFD();
172         shutdown0(nativefd, howto);
173     }
174 
175     // Intentional fallthrough after SO_REUSEADDR
176     @SuppressWarnings("fallthrough")
socketSetOption(int opt, boolean on, Object value)177     void socketSetOption(int opt, boolean on, Object value)
178         throws SocketException {
179         int nativefd = checkAndReturnNativeFD();
180 
181         if (opt == SO_TIMEOUT) {  // timeout implemented through select.
182             return;
183         }
184 
185         int optionValue = 0;
186 
187         switch(opt) {
188             case SO_REUSEADDR :
189                 if (exclusiveBind) {
190                     // SO_REUSEADDR emulated when using exclusive bind
191                     isReuseAddress = on;
192                     return;
193                 }
194                 // intentional fallthrough
195             case TCP_NODELAY :
196             case SO_OOBINLINE :
197             case SO_KEEPALIVE :
198                 optionValue = on ? 1 : 0;
199                 break;
200             case SO_SNDBUF :
201             case SO_RCVBUF :
202             case IP_TOS :
203                 optionValue = ((Integer)value).intValue();
204                 break;
205             case SO_LINGER :
206                 if (on) {
207                     optionValue =  ((Integer)value).intValue();
208                 } else {
209                     optionValue = -1;
210                 }
211                 break;
212             default :/* shouldn't get here */
213                 throw new SocketException("Option not supported");
214         }
215 
216         setIntOption(nativefd, opt, optionValue);
217     }
218 
socketGetOption(int opt, Object iaContainerObj)219     int socketGetOption(int opt, Object iaContainerObj) throws SocketException {
220         int nativefd = checkAndReturnNativeFD();
221 
222         // SO_BINDADDR is not a socket option.
223         if (opt == SO_BINDADDR) {
224             localAddress(nativefd, (InetAddressContainer)iaContainerObj);
225             return 0;  // return value doesn't matter.
226         }
227 
228         // SO_REUSEADDR emulated when using exclusive bind
229         if (opt == SO_REUSEADDR && exclusiveBind)
230             return isReuseAddress? 1 : -1;
231 
232         int value = getIntOption(nativefd, opt);
233 
234         switch (opt) {
235             case TCP_NODELAY :
236             case SO_OOBINLINE :
237             case SO_KEEPALIVE :
238             case SO_REUSEADDR :
239                 return (value == 0) ? -1 : 1;
240         }
241         return value;
242     }
243 
socketSendUrgentData(int data)244     void socketSendUrgentData(int data) throws IOException {
245         int nativefd = checkAndReturnNativeFD();
246         sendOOB(nativefd, data);
247     }
248 
checkAndReturnNativeFD()249     private int checkAndReturnNativeFD() throws SocketException {
250         if (fd == null || !fd.valid())
251             throw new SocketException("Socket closed");
252 
253         return fdAccess.get(fd);
254     }
255 
256     static final int WOULDBLOCK = -2;       // Nothing available (non-blocking)
257 
258     static {
initIDs()259         initIDs();
260     }
261 
262     /* Native methods */
263 
initIDs()264     static native void initIDs();
265 
socket0(boolean stream, boolean v6Only)266     static native int socket0(boolean stream, boolean v6Only) throws IOException;
267 
bind0(int fd, InetAddress localAddress, int localport, boolean exclBind)268     static native void bind0(int fd, InetAddress localAddress, int localport,
269                              boolean exclBind)
270         throws IOException;
271 
connect0(int fd, InetAddress remote, int remotePort)272     static native int connect0(int fd, InetAddress remote, int remotePort)
273         throws IOException;
274 
waitForConnect(int fd, int timeout)275     static native void waitForConnect(int fd, int timeout) throws IOException;
276 
localPort0(int fd)277     static native int localPort0(int fd) throws IOException;
278 
localAddress(int fd, InetAddressContainer in)279     static native void localAddress(int fd, InetAddressContainer in) throws SocketException;
280 
listen0(int fd, int backlog)281     static native void listen0(int fd, int backlog) throws IOException;
282 
accept0(int fd, InetSocketAddress[] isaa)283     static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException;
284 
waitForNewConnection(int fd, int timeout)285     static native void waitForNewConnection(int fd, int timeout) throws IOException;
286 
available0(int fd)287     static native int available0(int fd) throws IOException;
288 
close0(int fd)289     static native void close0(int fd) throws IOException;
290 
shutdown0(int fd, int howto)291     static native void shutdown0(int fd, int howto) throws IOException;
292 
setIntOption(int fd, int cmd, int optionValue)293     static native void setIntOption(int fd, int cmd, int optionValue) throws SocketException;
294 
getIntOption(int fd, int cmd)295     static native int getIntOption(int fd, int cmd) throws SocketException;
296 
sendOOB(int fd, int data)297     static native void sendOOB(int fd, int data) throws IOException;
298 
configureBlocking(int fd, boolean blocking)299     static native void configureBlocking(int fd, boolean blocking) throws IOException;
300 }
301