1 /* 2 * Copyright (c) 1996, 2016, 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.FileDescriptor; 28 import java.io.IOException; 29 import java.security.AccessController; 30 import sun.net.ResourceManager; 31 import java.util.Set; 32 import java.util.HashSet; 33 import java.util.Collections; 34 35 /** 36 * Abstract datagram and multicast socket implementation base class. 37 * Note: This is not a public class, so that applets cannot call 38 * into the implementation directly and hence cannot bypass the 39 * security checks present in the DatagramSocket and MulticastSocket 40 * classes. 41 * 42 * @author Pavani Diwanji 43 */ 44 45 abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl 46 { 47 /* timeout value for receive() */ 48 int timeout = 0; 49 boolean connected = false; 50 private int trafficClass = 0; 51 protected InetAddress connectedAddress = null; 52 private int connectedPort = -1; 53 54 private static final String os = AccessController.doPrivileged( 55 new sun.security.action.GetPropertyAction("os.name") 56 ); 57 58 /** 59 * flag set if the native connect() call not to be used 60 */ 61 private static final boolean connectDisabled = os.contains("OS X"); 62 63 /** 64 * Load net library into runtime. 65 */ 66 static { 67 java.security.AccessController.doPrivileged( 68 new java.security.PrivilegedAction<>() { 69 public Void run() { 70 System.loadLibrary("net"); 71 return null; 72 } 73 }); 74 } 75 76 private static volatile boolean checkedReusePort; 77 private static volatile boolean isReusePortAvailable; 78 79 /** 80 * Tells whether SO_REUSEPORT is supported. 81 */ 82 static boolean isReusePortAvailable() { 83 if (!checkedReusePort) { 84 isReusePortAvailable = isReusePortAvailable0(); 85 checkedReusePort = true; 86 } 87 return isReusePortAvailable; 88 } 89 90 private static volatile Set<SocketOption<?>> socketOptions; 91 92 /** 93 * Returns a set of SocketOptions supported by this impl 94 * and by this impl's socket (Socket or ServerSocket) 95 * 96 * @return a Set of SocketOptions 97 */ 98 @Override 99 protected Set<SocketOption<?>> supportedOptions() { 100 Set<SocketOption<?>> options = socketOptions; 101 if (options == null) { 102 if (isReusePortAvailable()) { 103 options = new HashSet<>(); 104 options.addAll(super.supportedOptions()); 105 options.add(StandardSocketOptions.SO_REUSEPORT); 106 options = Collections.unmodifiableSet(options); 107 } else { 108 options = super.supportedOptions(); 109 } 110 socketOptions = options; 111 } 112 return options; 113 } 114 115 /** 116 * Creates a datagram socket 117 */ 118 protected synchronized void create() throws SocketException { 119 ResourceManager.beforeUdpCreate(); 120 fd = new FileDescriptor(); 121 try { 122 datagramSocketCreate(); 123 } catch (SocketException ioe) { 124 ResourceManager.afterUdpClose(); 125 fd = null; 126 throw ioe; 127 } 128 } 129 130 /** 131 * Binds a datagram socket to a local port. 132 */ 133 protected synchronized void bind(int lport, InetAddress laddr) 134 throws SocketException { 135 bind0(lport, laddr); 136 } 137 138 protected abstract void bind0(int lport, InetAddress laddr) 139 throws SocketException; 140 141 /** 142 * Sends a datagram packet. The packet contains the data and the 143 * destination address to send the packet to. 144 * @param p the packet to be sent. 145 */ 146 protected abstract void send(DatagramPacket p) throws IOException; 147 148 /** 149 * Connects a datagram socket to a remote destination. This associates the remote 150 * address with the local socket so that datagrams may only be sent to this destination 151 * and received from this destination. 152 * @param address the remote InetAddress to connect to 153 * @param port the remote port number 154 */ 155 protected void connect(InetAddress address, int port) throws SocketException { 156 connect0(address, port); 157 connectedAddress = address; 158 connectedPort = port; 159 connected = true; 160 } 161 162 /** 163 * Disconnects a previously connected socket. Does nothing if the socket was 164 * not connected already. 165 */ 166 protected void disconnect() { 167 disconnect0(connectedAddress.holder().getFamily()); 168 connected = false; 169 connectedAddress = null; 170 connectedPort = -1; 171 } 172 173 /** 174 * Peek at the packet to see who it is from. 175 * @param i the address to populate with the sender address 176 */ 177 protected abstract int peek(InetAddress i) throws IOException; 178 protected abstract int peekData(DatagramPacket p) throws IOException; 179 /** 180 * Receive the datagram packet. 181 * @param p the packet to receive into 182 */ 183 protected synchronized void receive(DatagramPacket p) 184 throws IOException { 185 receive0(p); 186 } 187 188 protected abstract void receive0(DatagramPacket p) 189 throws IOException; 190 191 /** 192 * Set the TTL (time-to-live) option. 193 * @param ttl TTL to be set. 194 */ 195 protected abstract void setTimeToLive(int ttl) throws IOException; 196 197 /** 198 * Get the TTL (time-to-live) option. 199 */ 200 protected abstract int getTimeToLive() throws IOException; 201 202 /** 203 * Set the TTL (time-to-live) option. 204 * @param ttl TTL to be set. 205 */ 206 @Deprecated 207 protected abstract void setTTL(byte ttl) throws IOException; 208 209 /** 210 * Get the TTL (time-to-live) option. 211 */ 212 @Deprecated 213 protected abstract byte getTTL() throws IOException; 214 215 /** 216 * Join the multicast group. 217 * @param inetaddr multicast address to join. 218 */ 219 protected void join(InetAddress inetaddr) throws IOException { 220 join(inetaddr, null); 221 } 222 223 /** 224 * Leave the multicast group. 225 * @param inetaddr multicast address to leave. 226 */ 227 protected void leave(InetAddress inetaddr) throws IOException { 228 leave(inetaddr, null); 229 } 230 /** 231 * Join the multicast group. 232 * @param mcastaddr multicast address to join. 233 * @param netIf specifies the local interface to receive multicast 234 * datagram packets 235 * @throws IllegalArgumentException if mcastaddr is null or is a 236 * SocketAddress subclass not supported by this socket 237 * @since 1.4 238 */ 239 240 protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) 241 throws IOException { 242 if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) 243 throw new IllegalArgumentException("Unsupported address type"); 244 join(((InetSocketAddress)mcastaddr).getAddress(), netIf); 245 } 246 247 protected abstract void join(InetAddress inetaddr, NetworkInterface netIf) 248 throws IOException; 249 250 /** 251 * Leave the multicast group. 252 * @param mcastaddr multicast address to leave. 253 * @param netIf specified the local interface to leave the group at 254 * @throws IllegalArgumentException if mcastaddr is null or is a 255 * SocketAddress subclass not supported by this socket 256 * @since 1.4 257 */ 258 protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) 259 throws IOException { 260 if (mcastaddr == null || !(mcastaddr instanceof InetSocketAddress)) 261 throw new IllegalArgumentException("Unsupported address type"); 262 leave(((InetSocketAddress)mcastaddr).getAddress(), netIf); 263 } 264 265 protected abstract void leave(InetAddress inetaddr, NetworkInterface netIf) 266 throws IOException; 267 268 /** 269 * Close the socket. 270 */ 271 protected void close() { 272 if (fd != null) { 273 datagramSocketClose(); 274 ResourceManager.afterUdpClose(); 275 fd = null; 276 } 277 } 278 279 protected boolean isClosed() { 280 return (fd == null) ? true : false; 281 } 282 283 protected void finalize() { 284 close(); 285 } 286 287 /** 288 * set a value - since we only support (setting) binary options 289 * here, o must be a Boolean 290 */ 291 292 public void setOption(int optID, Object o) throws SocketException { 293 if (isClosed()) { 294 throw new SocketException("Socket Closed"); 295 } 296 switch (optID) { 297 /* check type safety b4 going native. These should never 298 * fail, since only java.Socket* has access to 299 * PlainSocketImpl.setOption(). 300 */ 301 case SO_TIMEOUT: 302 if (o == null || !(o instanceof Integer)) { 303 throw new SocketException("bad argument for SO_TIMEOUT"); 304 } 305 int tmp = ((Integer) o).intValue(); 306 if (tmp < 0) 307 throw new IllegalArgumentException("timeout < 0"); 308 timeout = tmp; 309 return; 310 case IP_TOS: 311 if (o == null || !(o instanceof Integer)) { 312 throw new SocketException("bad argument for IP_TOS"); 313 } 314 trafficClass = ((Integer)o).intValue(); 315 break; 316 case SO_REUSEADDR: 317 if (o == null || !(o instanceof Boolean)) { 318 throw new SocketException("bad argument for SO_REUSEADDR"); 319 } 320 break; 321 case SO_BROADCAST: 322 if (o == null || !(o instanceof Boolean)) { 323 throw new SocketException("bad argument for SO_BROADCAST"); 324 } 325 break; 326 case SO_BINDADDR: 327 throw new SocketException("Cannot re-bind Socket"); 328 case SO_RCVBUF: 329 case SO_SNDBUF: 330 if (o == null || !(o instanceof Integer) || 331 ((Integer)o).intValue() < 0) { 332 throw new SocketException("bad argument for SO_SNDBUF or " + 333 "SO_RCVBUF"); 334 } 335 break; 336 case IP_MULTICAST_IF: 337 if (o == null || !(o instanceof InetAddress)) 338 throw new SocketException("bad argument for IP_MULTICAST_IF"); 339 break; 340 case IP_MULTICAST_IF2: 341 if (o == null || !(o instanceof NetworkInterface)) 342 throw new SocketException("bad argument for IP_MULTICAST_IF2"); 343 break; 344 case IP_MULTICAST_LOOP: 345 if (o == null || !(o instanceof Boolean)) 346 throw new SocketException("bad argument for IP_MULTICAST_LOOP"); 347 break; 348 case SO_REUSEPORT: 349 if (o == null || !(o instanceof Boolean)) { 350 throw new SocketException("bad argument for SO_REUSEPORT"); 351 } 352 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { 353 throw new UnsupportedOperationException("unsupported option"); 354 } 355 break; 356 default: 357 throw new SocketException("invalid option: " + optID); 358 } 359 socketSetOption(optID, o); 360 } 361 362 /* 363 * get option's state - set or not 364 */ 365 366 public Object getOption(int optID) throws SocketException { 367 if (isClosed()) { 368 throw new SocketException("Socket Closed"); 369 } 370 371 Object result; 372 373 switch (optID) { 374 case SO_TIMEOUT: 375 result = timeout; 376 break; 377 378 case IP_TOS: 379 result = socketGetOption(optID); 380 if ( ((Integer)result).intValue() == -1) { 381 result = trafficClass; 382 } 383 break; 384 385 case SO_BINDADDR: 386 case IP_MULTICAST_IF: 387 case IP_MULTICAST_IF2: 388 case SO_RCVBUF: 389 case SO_SNDBUF: 390 case IP_MULTICAST_LOOP: 391 case SO_REUSEADDR: 392 case SO_BROADCAST: 393 result = socketGetOption(optID); 394 break; 395 396 case SO_REUSEPORT: 397 if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { 398 throw new UnsupportedOperationException("unsupported option"); 399 } 400 result = socketGetOption(optID); 401 break; 402 403 default: 404 throw new SocketException("invalid option: " + optID); 405 } 406 407 return result; 408 } 409 410 protected abstract void datagramSocketCreate() throws SocketException; 411 protected abstract void datagramSocketClose(); 412 protected abstract void socketSetOption(int opt, Object val) 413 throws SocketException; 414 protected abstract Object socketGetOption(int opt) throws SocketException; 415 416 protected abstract void connect0(InetAddress address, int port) throws SocketException; 417 protected abstract void disconnect0(int family); 418 419 protected boolean nativeConnectDisabled() { 420 return connectDisabled; 421 } 422 423 abstract int dataAvailable(); 424 private static native boolean isReusePortAvailable0(); 425 }