1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 package java.net;
27 
28 import android.system.ErrnoException;
29 
30 import java.io.IOException;
31 import java.io.FileDescriptor;
32 import java.util.Set;
33 import java.util.HashSet;
34 import java.util.Collections;
35 import libcore.io.AsynchronousCloseMonitor;
36 import libcore.io.IoBridge;
37 import libcore.io.IoUtils;
38 import libcore.io.Libcore;
39 
40 import jdk.net.*;
41 
42 import static android.system.OsConstants.AF_INET6;
43 import static android.system.OsConstants.AF_UNIX;
44 import static android.system.OsConstants.EAGAIN;
45 import static android.system.OsConstants.EBADF;
46 import static android.system.OsConstants.EINVAL;
47 import static android.system.OsConstants.MSG_OOB;
48 import static android.system.OsConstants.POLLERR;
49 import static android.system.OsConstants.POLLIN;
50 import static android.system.OsConstants.SOCK_DGRAM;
51 import static android.system.OsConstants.SOCK_STREAM;
52 import static android.system.OsConstants.SHUT_RDWR;
53 import static sun.net.ExtendedOptionsImpl.*;
54 
55 // Android-changed: Rewritten to use android.system POSIX calls and assume AF_INET6.
56 /*
57  * On Unix systems we simply delegate to native methods.
58  *
59  * @author Chris Hegarty
60  */
61 
62 class PlainSocketImpl extends AbstractPlainSocketImpl
63 {
64     // Android-removed: Android doesn't need to call native initProto.
65     /*
66     static {
67         initProto();
68     }
69     */
70 
71     /**
72      * Constructs an empty instance.
73      */
PlainSocketImpl()74     PlainSocketImpl() {
75         // Android-changed: Let PlainSocketImpl construct its own FileDescriptor.
76         this.fd = new FileDescriptor();
77     }
78 
79     /**
80      * Constructs an instance with the given file descriptor.
81      */
82     // Android-removed: Let PlainSocketImpl construct its own FileDescriptor.
83     /*
84     PlainSocketImpl(FileDescriptor fd) {
85         this.fd = fd;
86     }
87     */
88 
setOption(SocketOption<T> name, T value)89     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
90         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
91             super.setOption(name, value);
92         } else {
93             if (isClosedOrPending()) {
94                 throw new SocketException("Socket closed");
95             }
96             checkSetOptionPermission(name);
97             checkValueType(value, SocketFlow.class);
98             setFlowOption(getFileDescriptor(), (SocketFlow)value);
99         }
100     }
101 
getOption(SocketOption<T> name)102     protected <T> T getOption(SocketOption<T> name) throws IOException {
103         if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
104             return super.getOption(name);
105         }
106         if (isClosedOrPending()) {
107             throw new SocketException("Socket closed");
108         }
109         checkGetOptionPermission(name);
110         SocketFlow flow = SocketFlow.create();
111         getFlowOption(getFileDescriptor(), flow);
112         return (T)flow;
113     }
114 
115     // BEGIN Android-changed: Rewrote on top of Libcore.io.
socketSetOption(int opt, Object val)116     protected void socketSetOption(int opt, Object val) throws SocketException {
117         try {
118             socketSetOption0(opt, val);
119         } catch (SocketException se) {
120             if (socket == null || !socket.isConnected())
121                 throw se;
122         }
123     }
124 
socketCreate(boolean isStream)125     void socketCreate(boolean isStream) throws IOException {
126         // The fd object must not change after calling bind, because we rely on this undocumented
127         // behaviour. See libcore.java.net.SocketTest#testFileDescriptorStaysSame.
128         fd.setInt$(IoBridge.socket(AF_INET6, isStream ? SOCK_STREAM : SOCK_DGRAM, 0).getInt$());
129         IoUtils.setFdOwner(fd, this);
130 
131         if (serverSocket != null) {
132             IoUtils.setBlocking(fd, false);
133             IoBridge.setSocketOption(fd, SO_REUSEADDR, true);
134         }
135     }
136 
socketConnect(InetAddress address, int port, int timeout)137     void socketConnect(InetAddress address, int port, int timeout) throws IOException {
138         if (fd == null || !fd.valid()) {
139             throw new SocketException("Socket closed");
140         }
141 
142         IoBridge.connect(fd, address, port, timeout);
143 
144         this.address = address;
145         this.port = port;
146 
147         if (localport == 0) {
148             // If socket is pending close, fd becomes an AF_UNIX socket and calling
149             // getLocalInetSocketAddress will fail.
150             // http://b/34645743
151             if (!isClosedOrPending()) {
152                 localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
153             }
154         }
155     }
156 
socketBind(InetAddress address, int port)157     void socketBind(InetAddress address, int port) throws IOException {
158         if (fd == null || !fd.valid()) {
159             throw new SocketException("Socket closed");
160         }
161 
162         IoBridge.bind(fd, address, port);
163 
164         this.address = address;
165         if (port == 0) {
166             // Now that we're a connected socket, let's extract the port number that the system
167             // chose for us and store it in the Socket object.
168             localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
169         } else {
170             localport = port;
171         }
172     }
173 
socketListen(int count)174     void socketListen(int count) throws IOException {
175         if (fd == null || !fd.valid()) {
176             throw new SocketException("Socket closed");
177         }
178 
179         try {
180             Libcore.os.listen(fd, count);
181         } catch (ErrnoException errnoException) {
182             throw errnoException.rethrowAsSocketException();
183         }
184     }
185 
socketAccept(SocketImpl s)186     void socketAccept(SocketImpl s) throws IOException {
187         if (fd == null || !fd.valid()) {
188             throw new SocketException("Socket closed");
189         }
190 
191         // poll() with a timeout of 0 means "poll for zero millis", but a Socket timeout == 0 means
192         // "wait forever". When timeout == 0 we pass -1 to poll.
193         if (timeout <= 0) {
194             IoBridge.poll(fd, POLLIN | POLLERR, -1);
195         } else {
196             IoBridge.poll(fd, POLLIN | POLLERR, timeout);
197         }
198 
199         InetSocketAddress peerAddress = new InetSocketAddress();
200         try {
201             FileDescriptor newfd = Libcore.os.accept(fd, peerAddress);
202 
203             s.fd.setInt$(newfd.getInt$());
204             IoUtils.setFdOwner(s.fd, s);
205             s.address = peerAddress.getAddress();
206             s.port = peerAddress.getPort();
207         } catch (ErrnoException errnoException) {
208             if (errnoException.errno == EAGAIN) {
209                 SocketTimeoutException e = new SocketTimeoutException();
210                 e.initCause(errnoException);
211                 throw e;
212             } else if (errnoException.errno == EINVAL || errnoException.errno == EBADF) {
213                 throw new SocketException("Socket closed", errnoException);
214             }
215             errnoException.rethrowAsSocketException();
216         }
217 
218         s.localport = IoBridge.getLocalInetSocketAddress(s.fd).getPort();
219     }
220 
socketAvailable()221     int socketAvailable() throws IOException {
222         return IoBridge.available(fd);
223     }
224 
socketClose0(boolean useDeferredClose)225     void socketClose0(boolean useDeferredClose) throws IOException {
226         if (fd == null || !fd.valid()) {
227             throw new SocketException("socket already closed");
228         }
229 
230         FileDescriptor markerFD = null;
231         if (useDeferredClose) {
232             markerFD = getMarkerFD();
233         }
234 
235         if (useDeferredClose && markerFD != null) {
236             try {
237                 Libcore.os.dup2(markerFD, fd.getInt$());
238                 Libcore.os.close(markerFD);
239 
240                 // This effectively closes the socket, needs to signal threads that blocks on this
241                 // file descriptor.
242                 AsynchronousCloseMonitor.signalBlockedThreads(fd);
243             } catch (ErrnoException errnoException) {
244                 // close should not throw
245             }
246         } else {
247             // If requested or a markerFD cannot be created, a non-deferred close is performed
248             // instead.
249             IoBridge.closeAndSignalBlockedThreads(fd);
250         }
251     }
252 
253     /*
254      * Create the marker file descriptor by establishing a loopback connection which we shutdown but
255      * do not close the fd. The result is an fd that can be used for read/write.
256      *
257      * The purpose is to keep hold of the raw fd handle until we are sure it is not used in any
258      * thread. Otherwise if we close the file descriptor directly, the system might reuse the raw fd
259      * number and threads holding old fd value might behave incorrectly.
260      */
getMarkerFD()261     private FileDescriptor getMarkerFD() throws SocketException {
262         FileDescriptor fd1 = new FileDescriptor();
263         FileDescriptor fd2 = new FileDescriptor();
264         try {
265             Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd1, fd2);
266 
267             // Shutdown fd1, any reads to this fd will get EOF; any writes will get an error.
268             Libcore.os.shutdown(fd1, SHUT_RDWR);
269             Libcore.os.close(fd2);
270         } catch (ErrnoException errnoException) {
271             // We might have reached the maximum file descriptor number and socketpair(2) would
272             // fail. In this case, return null and let caller to fall back to an alternative method
273             // that does not allocate more file descriptors.
274             return null;
275         }
276         return fd1;
277     }
278 
socketShutdown(int howto)279     void socketShutdown(int howto) throws IOException {
280         try {
281             Libcore.os.shutdown(fd, howto);
282         } catch (ErrnoException errnoException) {
283             throw errnoException.rethrowAsIOException();
284         }
285     }
286 
socketSetOption0(int cmd, Object value)287     void socketSetOption0(int cmd, Object value) throws SocketException {
288         // OpenJDK does not set SO_TIMEOUT on Linux.
289         if (cmd == SO_TIMEOUT) {
290             return;
291         }
292 
293         IoBridge.setSocketOption(fd, cmd, value);
294     }
295 
socketGetOption(int opt)296     Object socketGetOption(int opt) throws SocketException {
297         return IoBridge.getSocketOption(fd, opt);
298     }
299 
socketSendUrgentData(int data)300     void socketSendUrgentData(int data) throws IOException {
301         if (fd == null || !fd.valid()) {
302             throw new SocketException("Socket closed");
303         }
304 
305         try {
306             byte[] buffer = new byte[] { (byte) data };
307             Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0);
308         } catch (ErrnoException errnoException) {
309             throw errnoException.rethrowAsSocketException();
310         }
311     }
312     // END Android-changed: Rewrote on top of Libcore.io.
313 
314 }
315