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