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.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 final 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 { init()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 TwoStacksPlainDatagramSocketImpl(boolean exclBind, boolean isMulticast)81 TwoStacksPlainDatagramSocketImpl(boolean exclBind, boolean isMulticast) { 82 super(isMulticast); 83 exclusiveBind = exclBind; 84 } 85 create()86 protected synchronized void create() throws SocketException { 87 fd1 = new FileDescriptor(); 88 try { 89 super.create(); 90 // make SocketCleanable treat fd1 as a stream socket 91 // to avoid touching the counter in ResourceManager 92 SocketCleanable.register(fd1, true); 93 } catch (SocketException e) { 94 fd1 = null; 95 throw e; 96 } 97 } 98 bind(int lport, InetAddress laddr)99 protected synchronized void bind(int lport, InetAddress laddr) 100 throws SocketException { 101 super.bind(lport, laddr); 102 if (laddr.isAnyLocalAddress()) { 103 anyLocalBoundAddr = laddr; 104 } 105 } 106 107 @Override bind0(int lport, InetAddress laddr)108 protected synchronized void bind0(int lport, InetAddress laddr) 109 throws SocketException 110 { 111 // The native bind0 may close one or both of the underlying file 112 // descriptors, and even create new sockets, so the safest course of 113 // action is to unregister the socket cleaners, and register afterwards. 114 SocketCleanable.unregister(fd); 115 SocketCleanable.unregister(fd1); 116 117 bind0(lport, laddr, exclusiveBind); 118 119 SocketCleanable.register(fd, false); 120 // make SocketCleanable treat fd1 as a stream socket 121 // to avoid touching the counter in ResourceManager 122 SocketCleanable.register(fd1, true); 123 } 124 receive(DatagramPacket p)125 protected synchronized void receive(DatagramPacket p) 126 throws IOException { 127 try { 128 receive0(p); 129 } finally { 130 fduse = -1; 131 } 132 } 133 getOption(int optID)134 public Object getOption(int optID) throws SocketException { 135 if (isClosed()) { 136 throw new SocketException("Socket Closed"); 137 } 138 139 if (optID == SO_BINDADDR) { 140 if ((fd != null && fd1 != null) && !connected) { 141 return anyLocalBoundAddr; 142 } 143 int family = connectedAddress == null ? -1 : connectedAddress.holder().getFamily(); 144 return socketLocalAddress(family); 145 } else if (optID == SO_REUSEADDR && reuseAddressEmulated) { 146 return isReuseAddress; 147 } else if (optID == SO_REUSEPORT) { 148 // SO_REUSEPORT is not supported on Windows. 149 throw new UnsupportedOperationException("unsupported option"); 150 } else { 151 return super.getOption(optID); 152 } 153 } 154 socketSetOption(int opt, Object val)155 protected void socketSetOption(int opt, Object val) 156 throws SocketException 157 { 158 if (opt == SO_REUSEADDR && exclusiveBind && localPort != 0) { 159 // socket already bound, emulate 160 reuseAddressEmulated = true; 161 isReuseAddress = (Boolean)val; 162 } else if (opt == SO_REUSEPORT) { 163 // SO_REUSEPORT is not supported on Windows. 164 throw new UnsupportedOperationException("unsupported option"); 165 } else { 166 socketNativeSetOption(opt, val); 167 } 168 169 } 170 isClosed()171 protected boolean isClosed() { 172 return (fd == null && fd1 == null) ? true : false; 173 } 174 close()175 protected void close() { 176 if (fd != null || fd1 != null) { 177 SocketCleanable.unregister(fd); 178 SocketCleanable.unregister(fd1); 179 datagramSocketClose(); 180 ResourceManager.afterUdpClose(); 181 fd = null; 182 fd1 = null; 183 } 184 } 185 186 /* Native methods */ 187 bind0(int lport, InetAddress laddr, boolean exclBind)188 protected synchronized native void bind0(int lport, InetAddress laddr, 189 boolean exclBind) 190 throws SocketException; 191 send0(DatagramPacket p)192 protected native void send0(DatagramPacket p) throws IOException; 193 peek(InetAddress i)194 protected synchronized native int peek(InetAddress i) throws IOException; 195 peekData(DatagramPacket p)196 protected synchronized native int peekData(DatagramPacket p) throws IOException; 197 receive0(DatagramPacket p)198 protected synchronized native void receive0(DatagramPacket p) 199 throws IOException; 200 setTimeToLive(int ttl)201 protected native void setTimeToLive(int ttl) throws IOException; 202 getTimeToLive()203 protected native int getTimeToLive() throws IOException; 204 205 @Deprecated setTTL(byte ttl)206 protected native void setTTL(byte ttl) throws IOException; 207 208 @Deprecated getTTL()209 protected native byte getTTL() throws IOException; 210 join(InetAddress inetaddr, NetworkInterface netIf)211 protected native void join(InetAddress inetaddr, NetworkInterface netIf) 212 throws IOException; 213 leave(InetAddress inetaddr, NetworkInterface netIf)214 protected native void leave(InetAddress inetaddr, NetworkInterface netIf) 215 throws IOException; 216 datagramSocketCreate()217 protected native void datagramSocketCreate() throws SocketException; 218 datagramSocketClose()219 protected native void datagramSocketClose(); 220 socketNativeSetOption(int opt, Object val)221 protected native void socketNativeSetOption(int opt, Object val) 222 throws SocketException; 223 socketGetOption(int opt)224 protected native Object socketGetOption(int opt) throws SocketException; 225 connect0(InetAddress address, int port)226 protected native void connect0(InetAddress address, int port) throws SocketException; 227 socketLocalAddress(int family)228 protected native Object socketLocalAddress(int family) throws SocketException; 229 disconnect0(int family)230 protected native void disconnect0(int family); 231 dataAvailable()232 native int dataAvailable(); 233 234 /** 235 * Perform class load-time initializations. 236 */ init()237 private static native void init(); 238 } 239