View Javadoc
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 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<Void>() {
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 = new Integer(timeout);
326                 break;
327 
328             case IP_TOS:
329                 result = socketGetOption(optID);
330                 if ( ((Integer)result).intValue() == -1) {
331                     result = new Integer(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 }