AbstractPlainDatagramSocketImpl.java revision 12745:f068a4ffddd2
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 */
25package java.net;
26
27import java.io.FileDescriptor;
28import java.io.IOException;
29import java.security.AccessController;
30import 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
42abstract 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 static final 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}
368