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