Home | History | Annotate | Download | only in net
      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