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