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