1 /*
2  * Copyright (c) 2007, 2015, 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 sun.misc.SharedSecrets;
29 import sun.misc.JavaIOFileDescriptorAccess;
30 
31 /**
32  * This class defines the plain DatagramSocketImpl that is used on
33  * Windows platforms greater than or equal to Windows Vista. These
34  * platforms have a dual layer TCP/IP stack and can handle both IPv4
35  * and IPV6 through a single file descriptor.
36  * <p>
37  * Note: Multicasting on a dual layer TCP/IP stack is always done with
38  * TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
39  * of behavior defined for multicasting over a dual layer socket by the RFC.
40  *
41  * @author Chris Hegarty
42  */
43 
44 class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
45 {
46     static JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess();
47 
48     static {
initIDs()49         initIDs();
50     }
51 
52     // true if this socket is exclusively bound
53     private final boolean exclusiveBind;
54 
55     /*
56      * Set to true if SO_REUSEADDR is set after the socket is bound to
57      * indicate SO_REUSEADDR is being emulated
58      */
59     private boolean reuseAddressEmulated;
60 
61     // emulates SO_REUSEADDR when exclusiveBind is true and socket is bound
62     private boolean isReuseAddress;
63 
DualStackPlainDatagramSocketImpl(boolean exclBind)64     DualStackPlainDatagramSocketImpl(boolean exclBind) {
65         exclusiveBind = exclBind;
66     }
67 
datagramSocketCreate()68     protected void datagramSocketCreate() throws SocketException {
69         if (fd == null)
70             throw new SocketException("Socket closed");
71 
72         int newfd = socketCreate(false /* v6Only */);
73 
74         fdAccess.set(fd, newfd);
75     }
76 
bind0(int lport, InetAddress laddr)77     protected synchronized void bind0(int lport, InetAddress laddr)
78         throws SocketException {
79         int nativefd = checkAndReturnNativeFD();
80 
81         if (laddr == null)
82             throw new NullPointerException("argument address");
83 
84         socketBind(nativefd, laddr, lport, exclusiveBind);
85         if (lport == 0) {
86             localPort = socketLocalPort(nativefd);
87         } else {
88             localPort = lport;
89         }
90     }
91 
peek(InetAddress address)92     protected synchronized int peek(InetAddress address) throws IOException {
93         int nativefd = checkAndReturnNativeFD();
94 
95         if (address == null)
96             throw new NullPointerException("Null address in peek()");
97 
98         // Use peekData()
99         DatagramPacket peekPacket = new DatagramPacket(new byte[1], 1);
100         int peekPort = peekData(peekPacket);
101         address = peekPacket.getAddress();
102         return peekPort;
103     }
104 
peekData(DatagramPacket p)105     protected synchronized int peekData(DatagramPacket p) throws IOException {
106         int nativefd = checkAndReturnNativeFD();
107 
108         if (p == null)
109             throw new NullPointerException("packet");
110         if (p.getData() == null)
111             throw new NullPointerException("packet buffer");
112 
113         return socketReceiveOrPeekData(nativefd, p, timeout, connected, true /*peek*/);
114     }
115 
receive0(DatagramPacket p)116     protected synchronized void receive0(DatagramPacket p) throws IOException {
117         int nativefd = checkAndReturnNativeFD();
118 
119         if (p == null)
120             throw new NullPointerException("packet");
121         if (p.getData() == null)
122             throw new NullPointerException("packet buffer");
123 
124         socketReceiveOrPeekData(nativefd, p, timeout, connected, false /*receive*/);
125     }
126 
send(DatagramPacket p)127     protected void send(DatagramPacket p) throws IOException {
128         int nativefd = checkAndReturnNativeFD();
129 
130         if (p == null)
131             throw new NullPointerException("null packet");
132 
133         if (p.getAddress() == null ||p.getData() ==null)
134             throw new NullPointerException("null address || null buffer");
135 
136         socketSend(nativefd, p.getData(), p.getOffset(), p.getLength(),
137                    p.getAddress(), p.getPort(), connected);
138     }
139 
connect0(InetAddress address, int port)140     protected void connect0(InetAddress address, int port) throws SocketException {
141         int nativefd = checkAndReturnNativeFD();
142 
143         if (address == null)
144             throw new NullPointerException("address");
145 
146         socketConnect(nativefd, address, port);
147     }
148 
disconnect0(int family )149     protected void disconnect0(int family /*unused*/) {
150         if (fd == null || !fd.valid())
151             return;   // disconnect doesn't throw any exceptions
152 
153         socketDisconnect(fdAccess.get(fd));
154     }
155 
datagramSocketClose()156     protected void datagramSocketClose() {
157         if (fd == null || !fd.valid())
158             return;   // close doesn't throw any exceptions
159 
160         socketClose(fdAccess.get(fd));
161         fdAccess.set(fd, -1);
162     }
163 
164     @SuppressWarnings("fallthrough")
socketSetOption(int opt, Object val)165     protected void socketSetOption(int opt, Object val) throws SocketException {
166         int nativefd = checkAndReturnNativeFD();
167 
168         int optionValue = 0;
169 
170         switch(opt) {
171             case IP_TOS :
172             case SO_RCVBUF :
173             case SO_SNDBUF :
174                 optionValue = ((Integer)val).intValue();
175                 break;
176             case SO_REUSEADDR :
177                 if (exclusiveBind && localPort != 0)  {
178                     // socket already bound, emulate SO_REUSEADDR
179                     reuseAddressEmulated = true;
180                     isReuseAddress = (Boolean)val;
181                     return;
182                 }
183                 //Intentional fallthrough
184             case SO_BROADCAST :
185                 optionValue = ((Boolean)val).booleanValue() ? 1 : 0;
186                 break;
187             default: /* shouldn't get here */
188                 throw new SocketException("Option not supported");
189         }
190 
191         socketSetIntOption(nativefd, opt, optionValue);
192     }
193 
socketGetOption(int opt)194     protected Object socketGetOption(int opt) throws SocketException {
195         int nativefd = checkAndReturnNativeFD();
196 
197          // SO_BINDADDR is not a socket option.
198         if (opt == SO_BINDADDR) {
199             return socketLocalAddress(nativefd);
200         }
201         if (opt == SO_REUSEADDR && reuseAddressEmulated)
202             return isReuseAddress;
203 
204         int value = socketGetIntOption(nativefd, opt);
205         Object returnValue = null;
206 
207         switch (opt) {
208             case SO_REUSEADDR :
209             case SO_BROADCAST :
210                 returnValue =  (value == 0) ? Boolean.FALSE : Boolean.TRUE;
211                 break;
212             case IP_TOS :
213             case SO_RCVBUF :
214             case SO_SNDBUF :
215                 returnValue = new Integer(value);
216                 break;
217             default: /* shouldn't get here */
218                 throw new SocketException("Option not supported");
219         }
220 
221         return returnValue;
222     }
223 
224     /* Multicast specific methods.
225      * Multicasting on a dual layer TCP/IP stack is always done with
226      * TwoStacksPlainDatagramSocketImpl. This is to overcome the lack
227      * of behavior defined for multicasting over a dual layer socket by the RFC.
228      */
join(InetAddress inetaddr, NetworkInterface netIf)229     protected void join(InetAddress inetaddr, NetworkInterface netIf)
230         throws IOException {
231         throw new IOException("Method not implemented!");
232     }
233 
leave(InetAddress inetaddr, NetworkInterface netIf)234     protected void leave(InetAddress inetaddr, NetworkInterface netIf)
235         throws IOException {
236         throw new IOException("Method not implemented!");
237     }
238 
setTimeToLive(int ttl)239     protected void setTimeToLive(int ttl) throws IOException {
240         throw new IOException("Method not implemented!");
241     }
242 
getTimeToLive()243     protected int getTimeToLive() throws IOException {
244         throw new IOException("Method not implemented!");
245     }
246 
247     @Deprecated
setTTL(byte ttl)248     protected void setTTL(byte ttl) throws IOException {
249         throw new IOException("Method not implemented!");
250     }
251 
252     @Deprecated
getTTL()253     protected byte getTTL() throws IOException {
254         throw new IOException("Method not implemented!");
255     }
256     /* END Multicast specific methods */
257 
checkAndReturnNativeFD()258     private int checkAndReturnNativeFD() throws SocketException {
259         if (fd == null || !fd.valid())
260             throw new SocketException("Socket closed");
261 
262         return fdAccess.get(fd);
263     }
264 
265     /* Native methods */
266 
initIDs()267     private static native void initIDs();
268 
socketCreate(boolean v6Only)269     private static native int socketCreate(boolean v6Only);
270 
socketBind(int fd, InetAddress localAddress, int localport, boolean exclBind)271     private static native void socketBind(int fd, InetAddress localAddress,
272             int localport, boolean exclBind) throws SocketException;
273 
socketConnect(int fd, InetAddress address, int port)274     private static native void socketConnect(int fd, InetAddress address, int port)
275         throws SocketException;
276 
socketDisconnect(int fd)277     private static native void socketDisconnect(int fd);
278 
socketClose(int fd)279     private static native void socketClose(int fd);
280 
socketLocalPort(int fd)281     private static native int socketLocalPort(int fd) throws SocketException;
282 
socketLocalAddress(int fd)283     private static native Object socketLocalAddress(int fd) throws SocketException;
284 
socketReceiveOrPeekData(int fd, DatagramPacket packet, int timeout, boolean connected, boolean peek)285     private static native int socketReceiveOrPeekData(int fd, DatagramPacket packet,
286         int timeout, boolean connected, boolean peek) throws IOException;
287 
socketSend(int fd, byte[] data, int offset, int length, InetAddress address, int port, boolean connected)288     private static native void socketSend(int fd, byte[] data, int offset, int length,
289         InetAddress address, int port, boolean connected) throws IOException;
290 
socketSetIntOption(int fd, int cmd, int optionValue)291     private static native void socketSetIntOption(int fd, int cmd,
292         int optionValue) throws SocketException;
293 
socketGetIntOption(int fd, int cmd)294     private static native int socketGetIntOption(int fd, int cmd) throws SocketException;
295 
dataAvailable()296     native int dataAvailable();
297 }
298