1 /* 2 * Copyright (c) 2007, 2018, 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 jdk.internal.access.SharedSecrets; 29 import jdk.internal.access.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 { 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 64 DualStackPlainDatagramSocketImpl(boolean exclBind) { 65 exclusiveBind = exclBind; 66 } 67 68 protected void datagramSocketCreate() throws SocketException { 69 if (fd == null) 70 throw new SocketException("Socket closed"); 71 72 int newfd = socketCreate(); 73 74 fdAccess.set(fd, newfd); 75 } 76 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 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 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 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 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 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 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 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") 165 protected void socketSetOption(int opt, Object val) throws SocketException { 166 int nativefd = checkAndReturnNativeFD(); 167 168 int optionValue = 0; 169 170 // SO_REUSEPORT is not supported on Windows. 171 if (opt == SO_REUSEPORT) { 172 throw new UnsupportedOperationException("unsupported option"); 173 } 174 175 switch(opt) { 176 case IP_TOS : 177 case SO_RCVBUF : 178 case SO_SNDBUF : 179 optionValue = ((Integer)val).intValue(); 180 break; 181 case SO_REUSEADDR : 182 if (exclusiveBind && localPort != 0) { 183 // socket already bound, emulate SO_REUSEADDR 184 reuseAddressEmulated = true; 185 isReuseAddress = (Boolean)val; 186 return; 187 } 188 //Intentional fallthrough 189 case SO_BROADCAST : 190 optionValue = ((Boolean)val).booleanValue() ? 1 : 0; 191 break; 192 default: /* shouldn't get here */ 193 throw new SocketException("Option not supported"); 194 } 195 196 socketSetIntOption(nativefd, opt, optionValue); 197 } 198 199 protected Object socketGetOption(int opt) throws SocketException { 200 int nativefd = checkAndReturnNativeFD(); 201 202 // SO_BINDADDR is not a socket option. 203 if (opt == SO_BINDADDR) { 204 return socketLocalAddress(nativefd); 205 } 206 if (opt == SO_REUSEADDR && reuseAddressEmulated) 207 return isReuseAddress; 208 // SO_REUSEPORT is not supported on Windows. 209 if (opt == SO_REUSEPORT) 210 throw new UnsupportedOperationException("unsupported option"); 211 212 int value = socketGetIntOption(nativefd, opt); 213 Object returnValue = null; 214 215 switch (opt) { 216 case SO_REUSEADDR : 217 case SO_BROADCAST : 218 returnValue = (value == 0) ? Boolean.FALSE : Boolean.TRUE; 219 break; 220 case IP_TOS : 221 case SO_RCVBUF : 222 case SO_SNDBUF : 223 returnValue = Integer.valueOf(value); 224 break; 225 default: /* shouldn't get here */ 226 throw new SocketException("Option not supported"); 227 } 228 229 return returnValue; 230 } 231 232 /* Multicast specific methods. 233 * Multicasting on a dual layer TCP/IP stack is always done with 234 * TwoStacksPlainDatagramSocketImpl. This is to overcome the lack 235 * of behavior defined for multicasting over a dual layer socket by the RFC. 236 */ 237 protected void join(InetAddress inetaddr, NetworkInterface netIf) 238 throws IOException { 239 throw new IOException("Method not implemented!"); 240 } 241 242 protected void leave(InetAddress inetaddr, NetworkInterface netIf) 243 throws IOException { 244 throw new IOException("Method not implemented!"); 245 } 246 247 protected void setTimeToLive(int ttl) throws IOException { 248 throw new IOException("Method not implemented!"); 249 } 250 251 protected int getTimeToLive() throws IOException { 252 throw new IOException("Method not implemented!"); 253 } 254 255 @Deprecated 256 protected void setTTL(byte ttl) throws IOException { 257 throw new IOException("Method not implemented!"); 258 } 259 260 @Deprecated 261 protected byte getTTL() throws IOException { 262 throw new IOException("Method not implemented!"); 263 } 264 /* END Multicast specific methods */ 265 266 private int checkAndReturnNativeFD() throws SocketException { 267 if (fd == null || !fd.valid()) 268 throw new SocketException("Socket closed"); 269 270 return fdAccess.get(fd); 271 } 272 273 /* Native methods */ 274 275 private static native void initIDs(); 276 277 private static native int socketCreate(); 278 279 private static native void socketBind(int fd, InetAddress localAddress, 280 int localport, boolean exclBind) throws SocketException; 281 282 private static native void socketConnect(int fd, InetAddress address, int port) 283 throws SocketException; 284 285 private static native void socketDisconnect(int fd); 286 287 private static native void socketClose(int fd); 288 289 private static native int socketLocalPort(int fd) throws SocketException; 290 291 private static native Object socketLocalAddress(int fd) throws SocketException; 292 293 private static native int socketReceiveOrPeekData(int fd, DatagramPacket packet, 294 int timeout, boolean connected, boolean peek) throws IOException; 295 296 private static native void socketSend(int fd, byte[] data, int offset, int length, 297 InetAddress address, int port, boolean connected) throws IOException; 298 299 private static native void socketSetIntOption(int fd, int cmd, 300 int optionValue) throws SocketException; 301 302 private static native int socketGetIntOption(int fd, int cmd) throws SocketException; 303 304 native int dataAvailable(); 305 }