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 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 { 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(false /* v6Only */); 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 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 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 */ 229 protected void join(InetAddress inetaddr, NetworkInterface netIf) 230 throws IOException { 231 throw new IOException("Method not implemented!"); 232 } 233 234 protected void leave(InetAddress inetaddr, NetworkInterface netIf) 235 throws IOException { 236 throw new IOException("Method not implemented!"); 237 } 238 239 protected void setTimeToLive(int ttl) throws IOException { 240 throw new IOException("Method not implemented!"); 241 } 242 243 protected int getTimeToLive() throws IOException { 244 throw new IOException("Method not implemented!"); 245 } 246 247 @Deprecated 248 protected void setTTL(byte ttl) throws IOException { 249 throw new IOException("Method not implemented!"); 250 } 251 252 @Deprecated 253 protected byte getTTL() throws IOException { 254 throw new IOException("Method not implemented!"); 255 } 256 /* END Multicast specific methods */ 257 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 267 private static native void initIDs(); 268 269 private static native int socketCreate(boolean v6Only); 270 271 private static native void socketBind(int fd, InetAddress localAddress, 272 int localport, boolean exclBind) throws SocketException; 273 274 private static native void socketConnect(int fd, InetAddress address, int port) 275 throws SocketException; 276 277 private static native void socketDisconnect(int fd); 278 279 private static native void socketClose(int fd); 280 281 private static native int socketLocalPort(int fd) throws SocketException; 282 283 private static native Object socketLocalAddress(int fd) throws SocketException; 284 285 private static native int socketReceiveOrPeekData(int fd, DatagramPacket packet, 286 int timeout, boolean connected, boolean peek) throws IOException; 287 288 private static native void socketSend(int fd, byte[] data, int offset, int length, 289 InetAddress address, int port, boolean connected) throws IOException; 290 291 private static native void socketSetIntOption(int fd, int cmd, 292 int optionValue) throws SocketException; 293 294 private static native int socketGetIntOption(int fd, int cmd) throws SocketException; 295 }