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 java.io.FileDescriptor;
  28 import java.io.IOException;
  29 import java.security.AccessController;
  30 import sun.net.ResourceManager;
  31 
  32 /**
  33  * Abstract datagram and multicast socket implementation base class.
  34  * Note: This is not a public class, so that applets cannot call
  35  * into the implementation directly and hence cannot bypass the
  36  * security checks present in the DatagramSocket and MulticastSocket
  37  * classes.
  38  *
  39  * @author Pavani Diwanji
  40  */
  41 
  42 abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
  43 {
  44     /* timeout value for receive() */
  45     int timeout = 0;
  46     boolean connected = false;
  47     private int trafficClass = 0;
  48     protected InetAddress connectedAddress = null;
  49     private int connectedPort = -1;
  50 
  51     private static final String os = AccessController.doPrivileged(
  52         new sun.security.action.GetPropertyAction("os.name")
  53     );
  54 
  55     /**
  56      * flag set if the native connect() call not to be used
  57      */
  58     private final static boolean connectDisabled = os.contains("OS X");
  59 
  60     /**
  61      * Load net library into runtime.
  62      */
  63     static {
  64         java.security.AccessController.doPrivileged(
  65             new java.security.PrivilegedAction<>() {
  66                 public Void run() {
  67                     System.loadLibrary("net");
  68                     return null;
  69                 }
  70             });
  71     }
  72 
  73     /**
  74      * Creates a datagram socket
  75      */
  76     protected synchronized void create() throws SocketException {
  77         ResourceManager.beforeUdpCreate();
  78         fd = new FileDescriptor();
  79         try {
  80             datagramSocketCreate();
  81         } catch (SocketException ioe) {
  82             ResourceManager.afterUdpClose();
  83             fd = null;
  84             throw ioe;
  85         }
  86     }
  87 
  88     /**
  89      * Binds a datagram socket to a local port.
  90      */
  91     protected synchronized void bind(int lport, InetAddress laddr)
  92         throws SocketException {
  93         bind0(lport, laddr);
  94     }
  95 
  96     protected abstract void bind0(int lport, InetAddress laddr)
  97         throws SocketException;
  98 
  99     /**
 100      * Sends a datagram packet. The packet contains the data and the
 101      * destination address to send the packet to.
 102      * @param p the packet to be sent.
 103      */
 104     protected abstract void send(DatagramPacket p) throws IOException;
 105 
 106     /**
 107      * Connects a datagram socket to a remote destination. This associates the remote
 108      * address with the local socket so that datagrams may only be sent to this destination
 109      * and received from this destination.
 110      * @param address the remote InetAddress to connect to
 111      * @param port the remote port number
 112      */
 113     protected void connect(InetAddress address, int port) throws SocketException {
 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      */
 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      */
 135     protected abstract int peek(InetAddress i) throws IOException;
 136     protected abstract int peekData(DatagramPacket p) throws IOException;
 137     /**
 138      * Receive the datagram packet.
 139      * @param p the packet to receive into
 140      */
 141     protected synchronized void receive(DatagramPacket p)
 142         throws IOException {
 143         receive0(p);
 144     }
 145 
 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      */
 153     protected abstract void setTimeToLive(int ttl) throws IOException;
 154 
 155     /**
 156      * Get the TTL (time-to-live) option.
 157      */
 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
 165     protected abstract void setTTL(byte ttl) throws IOException;
 166 
 167     /**
 168      * Get the TTL (time-to-live) option.
 169      */
 170     @Deprecated
 171     protected abstract byte getTTL() throws IOException;
 172 
 173     /**
 174      * Join the multicast group.
 175      * @param inetaddr multicast address to join.
 176      */
 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      */
 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 
 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 
 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      */
 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 
 223     protected abstract void leave(InetAddress inetaddr, NetworkInterface netIf)
 224         throws IOException;
 225 
 226     /**
 227      * Close the socket.
 228      */
 229     protected void close() {
 230         if (fd != null) {
 231             datagramSocketClose();
 232             ResourceManager.afterUdpClose();
 233             fd = null;
 234         }
 235     }
 236 
 237     protected boolean isClosed() {
 238         return (fd == null) ? true : false;
 239     }
 240 
 241     protected void finalize() {
 242         close();
 243     }
 244 
 245     /**
 246      * set a value - since we only support (setting) binary options
 247      * here, o must be a Boolean
 248      */
 249 
 250      public void setOption(int optID, Object o) throws SocketException {
 251          if (isClosed()) {
 252              throw new SocketException("Socket Closed");
 253          }
 254          switch (optID) {
 255             /* check type safety b4 going native.  These should never
 256              * fail, since only java.Socket* has access to
 257              * PlainSocketImpl.setOption().
 258              */
 259          case SO_TIMEOUT:
 260              if (o == null || !(o instanceof Integer)) {
 261                  throw new SocketException("bad argument for SO_TIMEOUT");
 262              }
 263              int tmp = ((Integer) o).intValue();
 264              if (tmp < 0)
 265                  throw new IllegalArgumentException("timeout < 0");
 266              timeout = tmp;
 267              return;
 268          case IP_TOS:
 269              if (o == null || !(o instanceof Integer)) {
 270                  throw new SocketException("bad argument for IP_TOS");
 271              }
 272              trafficClass = ((Integer)o).intValue();
 273              break;
 274          case SO_REUSEADDR:
 275              if (o == null || !(o instanceof Boolean)) {
 276                  throw new SocketException("bad argument for SO_REUSEADDR");
 277              }
 278              break;
 279          case SO_BROADCAST:
 280              if (o == null || !(o instanceof Boolean)) {
 281                  throw new SocketException("bad argument for SO_BROADCAST");
 282              }
 283              break;
 284          case SO_BINDADDR:
 285              throw new SocketException("Cannot re-bind Socket");
 286          case SO_RCVBUF:
 287          case SO_SNDBUF:
 288              if (o == null || !(o instanceof Integer) ||
 289                  ((Integer)o).intValue() < 0) {
 290                  throw new SocketException("bad argument for SO_SNDBUF or " +
 291                                            "SO_RCVBUF");
 292              }
 293              break;
 294          case IP_MULTICAST_IF:
 295              if (o == null || !(o instanceof InetAddress))
 296                  throw new SocketException("bad argument for IP_MULTICAST_IF");
 297              break;
 298          case IP_MULTICAST_IF2:
 299              if (o == null || !(o instanceof NetworkInterface))
 300                  throw new SocketException("bad argument for IP_MULTICAST_IF2");
 301              break;
 302          case IP_MULTICAST_LOOP:
 303              if (o == null || !(o instanceof Boolean))
 304                  throw new SocketException("bad argument for IP_MULTICAST_LOOP");
 305              break;
 306          default:
 307              throw new SocketException("invalid option: " + optID);
 308          }
 309          socketSetOption(optID, o);
 310      }
 311 
 312     /*
 313      * get option's state - set or not
 314      */
 315 
 316     public Object getOption(int optID) throws SocketException {
 317         if (isClosed()) {
 318             throw new SocketException("Socket Closed");
 319         }
 320 
 321         Object result;
 322 
 323         switch (optID) {
 324             case SO_TIMEOUT:
 325                 result = timeout;
 326                 break;
 327 
 328             case IP_TOS:
 329                 result = socketGetOption(optID);
 330                 if ( ((Integer)result).intValue() == -1) {
 331                     result = trafficClass;
 332                 }
 333                 break;
 334 
 335             case SO_BINDADDR:
 336             case IP_MULTICAST_IF:
 337             case IP_MULTICAST_IF2:
 338             case SO_RCVBUF:
 339             case SO_SNDBUF:
 340             case IP_MULTICAST_LOOP:
 341             case SO_REUSEADDR:
 342             case SO_BROADCAST:
 343                 result = socketGetOption(optID);
 344                 break;
 345 
 346             default:
 347                 throw new SocketException("invalid option: " + optID);
 348         }
 349 
 350         return result;
 351     }
 352 
 353     protected abstract void datagramSocketCreate() throws SocketException;
 354     protected abstract void datagramSocketClose();
 355     protected abstract void socketSetOption(int opt, Object val)
 356         throws SocketException;
 357     protected abstract Object socketGetOption(int opt) throws SocketException;
 358 
 359     protected abstract void connect0(InetAddress address, int port) throws SocketException;
 360     protected abstract void disconnect0(int family);
 361 
 362     protected boolean nativeConnectDisabled() {
 363         return connectDisabled;
 364     }
 365 
 366     abstract int dataAvailable();
 367 }