PlainSocketImpl.java revision e95428629d4f519567f113b92ed1b09009673a6e
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 */
26package java.net;
27
28import android.system.ErrnoException;
29
30import java.io.IOException;
31import java.io.FileDescriptor;
32import java.util.Set;
33import java.util.HashSet;
34import java.util.Collections;
35import libcore.io.AsynchronousCloseMonitor;
36import libcore.io.IoBridge;
37import libcore.io.IoUtils;
38import libcore.io.Libcore;
39
40import jdk.net.*;
41
42import static android.system.OsConstants.AF_INET6;
43import static android.system.OsConstants.AF_UNIX;
44import static android.system.OsConstants.EAGAIN;
45import static android.system.OsConstants.EBADF;
46import static android.system.OsConstants.EINVAL;
47import static android.system.OsConstants.MSG_OOB;
48import static android.system.OsConstants.POLLERR;
49import static android.system.OsConstants.POLLIN;
50import static android.system.OsConstants.SOCK_DGRAM;
51import static android.system.OsConstants.SOCK_STREAM;
52import static android.system.OsConstants.SHUT_RDWR;
53import 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
62class PlainSocketImpl extends AbstractPlainSocketImpl
63{
64    /**
65     * Constructs an empty instance.
66     */
67    PlainSocketImpl() {
68        this(new FileDescriptor());
69    }
70
71    /**
72     * Constructs an instance with the given file descriptor.
73     */
74    PlainSocketImpl(FileDescriptor fd) {
75        this.fd = fd;
76    }
77
78    protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
79        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
80            super.setOption(name, value);
81        } else {
82            if (isClosedOrPending()) {
83                throw new SocketException("Socket closed");
84            }
85            checkSetOptionPermission(name);
86            checkValueType(value, SocketFlow.class);
87            setFlowOption(getFileDescriptor(), (SocketFlow)value);
88        }
89    }
90
91    protected <T> T getOption(SocketOption<T> name) throws IOException {
92        if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) {
93            return super.getOption(name);
94        }
95        if (isClosedOrPending()) {
96            throw new SocketException("Socket closed");
97        }
98        checkGetOptionPermission(name);
99        SocketFlow flow = SocketFlow.create();
100        getFlowOption(getFileDescriptor(), flow);
101        return (T)flow;
102    }
103
104    protected void socketSetOption(int opt, Object val) throws SocketException {
105        try {
106            socketSetOption0(opt, val);
107        } catch (SocketException se) {
108            if (socket == null || !socket.isConnected())
109                throw se;
110        }
111    }
112
113    void socketCreate(boolean isStream) throws IOException {
114        // The fd object must not change after calling bind, because we rely on this undocumented
115        // behaviour. See libcore.java.net.SocketTest#testFileDescriptorStaysSame.
116        fd.setInt$(IoBridge.socket(AF_INET6, isStream ? SOCK_STREAM : SOCK_DGRAM, 0).getInt$());
117
118        if (serverSocket != null) {
119            IoUtils.setBlocking(fd, false);
120            IoBridge.setSocketOption(fd, SO_REUSEADDR, true);
121        }
122    }
123
124    void socketConnect(InetAddress address, int port, int timeout) throws IOException {
125        if (fd == null || !fd.valid()) {
126            throw new SocketException("Socket closed");
127        }
128
129        IoBridge.connect(fd, address, port, timeout);
130
131        this.address = address;
132        this.port = port;
133
134        if (localport == 0) {
135            // If socket is pending close, fd becomes an AF_UNIX socket and calling
136            // getLocalInetSocketAddress will fail.
137            // http://b/34645743
138            if (!isClosedOrPending()) {
139                localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
140            }
141        }
142    }
143
144    void socketBind(InetAddress address, int port) throws IOException {
145        if (fd == null || !fd.valid()) {
146            throw new SocketException("Socket closed");
147        }
148
149        IoBridge.bind(fd, address, port);
150
151        this.address = address;
152        if (port == 0) {
153            // Now that we're a connected socket, let's extract the port number that the system
154            // chose for us and store it in the Socket object.
155            localport = IoBridge.getLocalInetSocketAddress(fd).getPort();
156        } else {
157            localport = port;
158        }
159    }
160
161    void socketListen(int count) throws IOException {
162        if (fd == null || !fd.valid()) {
163            throw new SocketException("Socket closed");
164        }
165
166        try {
167            Libcore.os.listen(fd, count);
168        } catch (ErrnoException errnoException) {
169            throw errnoException.rethrowAsSocketException();
170        }
171    }
172
173    void socketAccept(SocketImpl s) throws IOException {
174        if (fd == null || !fd.valid()) {
175            throw new SocketException("Socket closed");
176        }
177
178        // poll() with a timeout of 0 means "poll for zero millis", but a Socket timeout == 0 means
179        // "wait forever". When timeout == 0 we pass -1 to poll.
180        if (timeout <= 0) {
181            IoBridge.poll(fd, POLLIN | POLLERR, -1);
182        } else {
183            IoBridge.poll(fd, POLLIN | POLLERR, timeout);
184        }
185
186        InetSocketAddress peerAddress = new InetSocketAddress();
187        try {
188            FileDescriptor newfd = Libcore.os.accept(fd, peerAddress);
189
190            s.fd.setInt$(newfd.getInt$());
191            s.address = peerAddress.getAddress();
192            s.port = peerAddress.getPort();
193        } catch (ErrnoException errnoException) {
194            if (errnoException.errno == EAGAIN) {
195                throw new SocketTimeoutException(errnoException);
196            } else if (errnoException.errno == EINVAL || errnoException.errno == EBADF) {
197                throw new SocketException("Socket closed");
198            }
199            errnoException.rethrowAsSocketException();
200        }
201
202        s.localport = IoBridge.getLocalInetSocketAddress(s.fd).getPort();
203    }
204
205    int socketAvailable() throws IOException {
206        return IoBridge.available(fd);
207    }
208
209    void socketClose0(boolean useDeferredClose) throws IOException {
210        if (fd == null || !fd.valid()) {
211            throw new SocketException("socket already closed");
212        }
213
214        FileDescriptor markerFD = null;
215        if (useDeferredClose) {
216            markerFD = getMarkerFD();
217        }
218
219        if (useDeferredClose && markerFD != null) {
220            try {
221                Libcore.os.dup2(markerFD, fd.getInt$());
222                Libcore.os.close(markerFD);
223
224                // This effectively closes the socket, needs to signal threads that blocks on this
225                // file descriptor.
226                AsynchronousCloseMonitor.signalBlockedThreads(fd);
227            } catch (ErrnoException errnoException) {
228                // close should not throw
229            }
230        } else {
231            // If requested or a markerFD cannot be created, a non-deferred close is performed
232            // instead.
233            IoBridge.closeAndSignalBlockedThreads(fd);
234        }
235    }
236
237    /*
238     * Create the marker file descriptor by establishing a loopback connection which we shutdown but
239     * do not close the fd. The result is an fd that can be used for read/write.
240     *
241     * The purpose is to keep hold of the raw fd handle until we are sure it is not used in any
242     * thread. Otherwise if we close the file descriptor directly, the system might reuse the raw fd
243     * number and threads holding old fd value might behave incorrectly.
244     */
245    private FileDescriptor getMarkerFD() throws SocketException {
246        FileDescriptor fd1 = new FileDescriptor();
247        FileDescriptor fd2 = new FileDescriptor();
248        try {
249            Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd1, fd2);
250
251            // Shutdown fd1, any reads to this fd will get EOF; any writes will get an error.
252            Libcore.os.shutdown(fd1, SHUT_RDWR);
253            Libcore.os.close(fd2);
254        } catch (ErrnoException errnoException) {
255            // We might have reached the maximum file descriptor number and socketpair(2) would
256            // fail. In this case, return null and let caller to fall back to an alternative method
257            // that does not allocate more file descriptors.
258            return null;
259        }
260        return fd1;
261    }
262
263    void socketShutdown(int howto) throws IOException {
264        try {
265            Libcore.os.shutdown(fd, howto);
266        } catch (ErrnoException errnoException) {
267            throw errnoException.rethrowAsIOException();
268        }
269    }
270
271    void socketSetOption0(int cmd, Object value) throws SocketException {
272        // OpenJDK does not set SO_TIMEOUT on Linux.
273        if (cmd == SO_TIMEOUT) {
274            return;
275        }
276
277        IoBridge.setSocketOption(fd, cmd, value);
278    }
279
280    Object socketGetOption(int opt) throws SocketException {
281        return IoBridge.getSocketOption(fd, opt);
282    }
283
284    void socketSendUrgentData(int data) throws IOException {
285        if (fd == null || !fd.valid()) {
286            throw new SocketException("Socket closed");
287        }
288
289        try {
290            byte[] buffer = new byte[] { (byte) data };
291            Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0);
292        } catch (ErrnoException errnoException) {
293            throw errnoException.rethrowAsSocketException();
294        }
295    }
296
297}
298