1 /*
2  * Copyright (c) 2007,2011, 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 android.system.ErrnoException;
28 import android.system.StructGroupReq;
29 
30 import java.io.IOException;
31 import libcore.io.IoBridge;
32 import libcore.io.Libcore;
33 import libcore.util.EmptyArray;
34 
35 import jdk.net.*;
36 
37 import static android.system.OsConstants.AF_INET6;
38 import static android.system.OsConstants.AF_UNSPEC;
39 import static android.system.OsConstants.IPPROTO_IP;
40 import static android.system.OsConstants.IP_MULTICAST_ALL;
41 import static android.system.OsConstants.MSG_PEEK;
42 import static android.system.OsConstants.POLLERR;
43 import static android.system.OsConstants.POLLIN;
44 import static android.system.OsConstants.SOCK_DGRAM;
45 import static libcore.io.IoBridge.JAVA_IP_MULTICAST_TTL;
46 import static libcore.io.IoBridge.JAVA_MCAST_JOIN_GROUP;
47 import static libcore.io.IoBridge.JAVA_MCAST_LEAVE_GROUP;
48 import static sun.net.ExtendedOptionsImpl.*;
49 
50 /*
51  * On Unix systems we simply delegate to native methods.
52  *
53  * @author Chris Hegarty
54  */
55 
56 class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
57 {
58     // Android-removed: init method has been removed
59     // static {
60     //     init();
61     // }
62 
setOption(SocketOption<T> name, T value)63     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
64         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
65             super.setOption(name, value);
66         } else {
67             if (isClosed()) {
68                 throw new SocketException("Socket closed");
69             }
70             checkSetOptionPermission(name);
71             checkValueType(value, SocketFlow.class);
72             setFlowOption(getFileDescriptor(), (SocketFlow)value);
73         }
74     }
75 
getOption(SocketOption<T> name)76     protected <T> T getOption(SocketOption<T> name) throws IOException {
77         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
78             return super.getOption(name);
79         }
80         if (isClosed()) {
81             throw new SocketException("Socket closed");
82         }
83         checkGetOptionPermission(name);
84         SocketFlow flow = SocketFlow.create();
85         getFlowOption(getFileDescriptor(), flow);
86         return (T)flow;
87     }
88 
socketSetOption(int opt, Object val)89     protected void socketSetOption(int opt, Object val) throws SocketException {
90         try {
91             socketSetOption0(opt, val);
92         } catch (SocketException se) {
93             if (!connected)
94                 throw se;
95         }
96     }
97 
bind0(int lport, InetAddress laddr)98     protected synchronized void bind0(int lport, InetAddress laddr) throws SocketException {
99         if (isClosed()) {
100             throw new SocketException("Socket closed");
101         }
102 
103         IoBridge.bind(fd, laddr, lport);
104 
105         if (lport == 0) {
106             // Now that we're a connected socket, let's extract the port number that the system
107             // chose for us and store it in the Socket object.
108             localPort = IoBridge.getLocalInetSocketAddress(fd).getPort();
109         } else {
110             localPort = lport;
111         }
112     }
113 
send(DatagramPacket p)114     protected void send(DatagramPacket p) throws IOException {
115         if (isClosed()) {
116             throw new SocketException("Socket closed");
117         }
118         if (p.getData() == null || p.getAddress() == null) {
119             throw new NullPointerException("null buffer || null address");
120         }
121 
122         int port = connected ? 0 : p.getPort();
123         InetAddress address = connected ? null : p.getAddress();
124         IoBridge.sendto(fd, p.getData(), p.getOffset(), p.getLength(), 0, address, port);
125     }
126 
peek(InetAddress i)127     protected synchronized int peek(InetAddress i) throws IOException {
128         DatagramPacket p = new DatagramPacket(EmptyArray.BYTE, 0);
129         doRecv(p, MSG_PEEK);
130         i.holder().address = p.getAddress().holder().address;
131         return p.getPort();
132     }
133 
peekData(DatagramPacket p)134     protected synchronized int peekData(DatagramPacket p) throws IOException {
135         doRecv(p, MSG_PEEK);
136         return p.getPort();
137     }
138 
receive0(DatagramPacket p)139     protected synchronized void receive0(DatagramPacket p) throws IOException {
140         doRecv(p, 0);
141     }
142 
doRecv(DatagramPacket p, int flags)143     private void doRecv(DatagramPacket p, int flags) throws IOException {
144         if (isClosed()) {
145             throw new SocketException("Socket closed");
146         }
147 
148         if (timeout != 0) {
149             IoBridge.poll(fd, POLLIN | POLLERR, timeout);
150         }
151 
152         IoBridge.recvfrom(false, fd, p.getData(), p.getOffset(), p.bufLength, flags, p,
153                 connected);
154     }
155 
setTimeToLive(int ttl)156     protected void setTimeToLive(int ttl) throws IOException {
157         IoBridge.setSocketOption(fd, JAVA_IP_MULTICAST_TTL, ttl);
158     }
159 
getTimeToLive()160     protected int getTimeToLive() throws IOException {
161         return (Integer) IoBridge.getSocketOption(fd, JAVA_IP_MULTICAST_TTL);
162     }
163 
setTTL(byte ttl)164     protected void setTTL(byte ttl) throws IOException {
165         setTimeToLive((int) ttl & 0xff);
166     }
167 
getTTL()168     protected byte getTTL() throws IOException {
169         return (byte) getTimeToLive();
170     }
171 
makeGroupReq(InetAddress gr_group, NetworkInterface networkInterface)172     private static StructGroupReq makeGroupReq(InetAddress gr_group,
173             NetworkInterface networkInterface) {
174         int gr_interface = (networkInterface != null) ? networkInterface.getIndex() : 0;
175         return new StructGroupReq(gr_interface, gr_group);
176     }
177 
join(InetAddress inetaddr, NetworkInterface netIf)178     protected void join(InetAddress inetaddr, NetworkInterface netIf) throws IOException {
179         if (isClosed()) {
180             throw new SocketException("Socket closed");
181         }
182 
183         IoBridge.setSocketOption(fd, JAVA_MCAST_JOIN_GROUP, makeGroupReq(inetaddr, netIf));
184     }
185 
leave(InetAddress inetaddr, NetworkInterface netIf)186     protected void leave(InetAddress inetaddr, NetworkInterface netIf)
187         throws IOException {
188         if (isClosed()) {
189             throw new SocketException("Socket closed");
190         }
191 
192         IoBridge.setSocketOption(fd, JAVA_MCAST_LEAVE_GROUP, makeGroupReq(inetaddr, netIf));
193     }
194 
datagramSocketCreate()195     protected void datagramSocketCreate() throws SocketException {
196         fd = IoBridge.socket(AF_INET6, SOCK_DGRAM, 0);
197         IoBridge.setSocketOption(fd, SO_BROADCAST, true);
198 
199         try {
200             Libcore.os.setsockoptInt(fd, IPPROTO_IP, IP_MULTICAST_ALL, 0);
201         } catch (ErrnoException errnoException) {
202             throw errnoException.rethrowAsSocketException();
203         }
204     }
205 
datagramSocketClose()206     protected void datagramSocketClose() {
207         try {
208             IoBridge.closeAndSignalBlockedThreads(fd);
209         } catch (IOException ignored) { }
210     }
211 
socketSetOption0(int opt, Object val)212     protected void socketSetOption0(int opt, Object val) throws SocketException {
213         if (isClosed()) {
214             throw new SocketException("Socket closed");
215         }
216 
217         IoBridge.setSocketOption(fd, opt, val);
218     }
219 
socketGetOption(int opt)220     protected Object socketGetOption(int opt) throws SocketException {
221         if (isClosed()) {
222             throw new SocketException("Socket closed");
223         }
224 
225         return IoBridge.getSocketOption(fd, opt);
226     }
227 
connect0(InetAddress address, int port)228     protected void connect0(InetAddress address, int port) throws SocketException {
229         if (isClosed()) {
230             throw new SocketException("Socket closed");
231         }
232 
233         IoBridge.connect(fd, address, port);
234     }
235 
disconnect0(int family)236     protected void disconnect0(int family) {
237         if (isClosed()) {
238             return;
239         }
240 
241         InetAddress inetAddressUnspec = new InetAddress();
242         inetAddressUnspec.holder().family = AF_UNSPEC;
243 
244         try {
245             IoBridge.connect(fd, inetAddressUnspec, 0);
246         } catch (SocketException ignored) { }
247     }
248 
249     // Android-removed: JNI has been removed
250     // /**
251     //  * Perform class load-time initializations.
252     //  */
253     // private native static void init();
254 }
255