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