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 */
25package java.net;
26
27import android.system.ErrnoException;
28import android.system.StructGroupReq;
29
30import java.io.IOException;
31import libcore.io.IoBridge;
32import libcore.io.Libcore;
33import libcore.util.EmptyArray;
34
35import jdk.net.*;
36
37import static android.system.OsConstants.AF_INET6;
38import static android.system.OsConstants.AF_UNSPEC;
39import static android.system.OsConstants.IPPROTO_IP;
40import static android.system.OsConstants.IP_MULTICAST_ALL;
41import static android.system.OsConstants.MSG_PEEK;
42import static android.system.OsConstants.POLLERR;
43import static android.system.OsConstants.POLLIN;
44import static android.system.OsConstants.SOCK_DGRAM;
45import static libcore.io.IoBridge.JAVA_IP_MULTICAST_TTL;
46import static libcore.io.IoBridge.JAVA_MCAST_JOIN_GROUP;
47import static libcore.io.IoBridge.JAVA_MCAST_LEAVE_GROUP;
48import static sun.net.ExtendedOptionsImpl.*;
49
50/*
51 * On Unix systems we simply delegate to native methods.
52 *
53 * @author Chris Hegarty
54 */
55
56class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl
57{
58    // Android-removed: init method has been removed
59    // static {
60    //     init();
61    // }
62
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
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
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
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
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
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
134    protected synchronized int peekData(DatagramPacket p) throws IOException {
135        doRecv(p, MSG_PEEK);
136        return p.getPort();
137    }
138
139    protected synchronized void receive0(DatagramPacket p) throws IOException {
140        doRecv(p, 0);
141    }
142
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
156    protected void setTimeToLive(int ttl) throws IOException {
157        IoBridge.setSocketOption(fd, JAVA_IP_MULTICAST_TTL, ttl);
158    }
159
160    protected int getTimeToLive() throws IOException {
161        return (Integer) IoBridge.getSocketOption(fd, JAVA_IP_MULTICAST_TTL);
162    }
163
164    protected void setTTL(byte ttl) throws IOException {
165        setTimeToLive((int) ttl & 0xff);
166    }
167
168    protected byte getTTL() throws IOException {
169        return (byte) getTimeToLive();
170    }
171
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
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
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
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
206    protected void datagramSocketClose() {
207        try {
208            IoBridge.closeAndSignalBlockedThreads(fd);
209        } catch (IOException ignored) { }
210    }
211
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
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
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
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