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