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