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