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