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 java.io.FileDescriptor; 29 import sun.net.ResourceManager; 30 31 /** 32 * This class defines the plain DatagramSocketImpl that is used for all 33 * Windows versions lower than Vista. It adds support for IPv6 on 34 * these platforms where available. 35 * 36 * For backward compatibility windows platforms that do not have IPv6 37 * support also use this implementation, and fd1 gets set to null 38 * during socket creation. 39 * 40 * @author Chris Hegarty 41 */ 42 43 class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl 44 { 45 /* Used for IPv6 on Windows only */ 46 private FileDescriptor fd1; 47 48 /* 49 * Needed for ipv6 on windows because we need to know 50 * if the socket was bound to ::0 or 0.0.0.0, when a caller 51 * asks for it. In this case, both sockets are used, but we 52 * don't know whether the caller requested ::0 or 0.0.0.0 53 * and need to remember it here. 54 */ 55 private InetAddress anyLocalBoundAddr=null; 56 57 private int fduse=-1; /* saved between peek() and receive() calls */ 58 59 /* saved between successive calls to receive, if data is detected 60 * on both sockets at same time. To ensure that one socket is not 61 * starved, they rotate using this field 62 */ 63 private int lastfd=-1; 64 65 static { 66 init(); 67 } 68 69 // true if this socket is exclusively bound 70 private final boolean exclusiveBind; 71 72 /* 73 * Set to true if SO_REUSEADDR is set after the socket is bound to 74 * indicate SO_REUSEADDR is being emulated 75 */ 76 private boolean reuseAddressEmulated; 77 78 // emulates SO_REUSEADDR when exclusiveBind is true and socket is bound 79 private boolean isReuseAddress; 80 81 TwoStacksPlainDatagramSocketImpl(boolean exclBind) { 82 exclusiveBind = exclBind; 83 } 84 85 protected synchronized void create() throws SocketException { 86 fd1 = new FileDescriptor(); 87 try { 88 super.create(); 89 SocketCleanable.register(fd1); 90 } catch (SocketException e) { 91 fd1 = null; 92 throw e; 93 } 94 } 95 96 protected synchronized void bind(int lport, InetAddress laddr) 97 throws SocketException { 98 super.bind(lport, laddr); 99 if (laddr.isAnyLocalAddress()) { 100 anyLocalBoundAddr = laddr; 101 } 102 } 103 104 @Override 105 protected synchronized void bind0(int lport, InetAddress laddr) 106 throws SocketException 107 { 108 // The native bind0 may close one or both of the underlying file 109 // descriptors, and even create new sockets, so the safest course of 110 // action is to unregister the socket cleaners, and register afterwards. 111 SocketCleanable.unregister(fd); 112 SocketCleanable.unregister(fd1); 113 114 bind0(lport, laddr, exclusiveBind); 115 116 SocketCleanable.register(fd); 117 SocketCleanable.register(fd1); 118 } 119 120 protected synchronized void receive(DatagramPacket p) 121 throws IOException { 122 try { 123 receive0(p); 124 } finally { 125 fduse = -1; 126 } 127 } 128 129 public Object getOption(int optID) throws SocketException { 130 if (isClosed()) { 131 throw new SocketException("Socket Closed"); 132 } 133 134 if (optID == SO_BINDADDR) { 135 if ((fd != null && fd1 != null) && !connected) { 136 return anyLocalBoundAddr; 137 } 138 int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily(); 139 return socketLocalAddress(family); 140 } else if (optID == SO_REUSEADDR && reuseAddressEmulated) { 141 return isReuseAddress; 142 } else if (optID == SO_REUSEPORT) { 143 // SO_REUSEPORT is not supported on Windows. 144 throw new UnsupportedOperationException("unsupported option"); 145 } else { 146 return super.getOption(optID); 147 } 148 } 149 150 protected void socketSetOption(int opt, Object val) 151 throws SocketException 152 { 153 if (opt == SO_REUSEADDR && exclusiveBind && localPort != 0) { 154 // socket already bound, emulate 155 reuseAddressEmulated = true; 156 isReuseAddress = (Boolean)val; 157 } else if (opt == SO_REUSEPORT) { 158 // SO_REUSEPORT is not supported on Windows. 159 throw new UnsupportedOperationException("unsupported option"); 160 } else { 161 socketNativeSetOption(opt, val); 162 } 163 164 } 165 166 protected boolean isClosed() { 167 return (fd == null && fd1 == null) ? true : false; 168 } 169 170 protected void close() { 171 if (fd != null || fd1 != null) { 172 SocketCleanable.unregister(fd); 173 SocketCleanable.unregister(fd1); 174 datagramSocketClose(); 175 ResourceManager.afterUdpClose(); 176 fd = null; 177 fd1 = null; 178 } 179 } 180 181 /* Native methods */ 182 183 protected synchronized native void bind0(int lport, InetAddress laddr, 184 boolean exclBind) 185 throws SocketException; 186 187 protected native void send(DatagramPacket p) throws IOException; 188 189 protected synchronized native int peek(InetAddress i) throws IOException; 190 191 protected synchronized native int peekData(DatagramPacket p) throws IOException; 192 193 protected synchronized native void receive0(DatagramPacket p) 194 throws IOException; 195 196 protected native void setTimeToLive(int ttl) throws IOException; 197 198 protected native int getTimeToLive() throws IOException; 199 200 @Deprecated 201 protected native void setTTL(byte ttl) throws IOException; 202 203 @Deprecated 204 protected native byte getTTL() throws IOException; 205 206 protected native void join(InetAddress inetaddr, NetworkInterface netIf) 207 throws IOException; 208 209 protected native void leave(InetAddress inetaddr, NetworkInterface netIf) 210 throws IOException; 211 212 protected native void datagramSocketCreate() throws SocketException; 213 214 protected native void datagramSocketClose(); 215 216 protected native void socketNativeSetOption(int opt, Object val) 217 throws SocketException; 218 219 protected native Object socketGetOption(int opt) throws SocketException; 220 221 protected native void connect0(InetAddress address, int port) throws SocketException; 222 223 protected native Object socketLocalAddress(int family) throws SocketException; 224 225 protected native void disconnect0(int family); 226 227 native int dataAvailable(); 228 229 /** 230 * Perform class load-time initializations. 231 */ 232 private static native void init(); 233 }