1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.net;
19
20import dalvik.system.CloseGuard;
21import java.io.FileDescriptor;
22import java.io.IOException;
23import java.io.InputStream;
24import java.io.OutputStream;
25import java.net.ConnectException;
26import java.net.InetAddress;
27import java.net.InetSocketAddress;
28import java.net.Proxy;
29import java.net.SocketAddress;
30import java.net.SocketException;
31import java.net.SocketImpl;
32import java.net.SocketTimeoutException;
33import java.net.UnknownHostException;
34import java.nio.ByteOrder;
35import java.util.Arrays;
36import libcore.io.ErrnoException;
37import libcore.io.IoBridge;
38import libcore.io.Libcore;
39import libcore.io.Memory;
40import libcore.io.Streams;
41import static libcore.io.OsConstants.*;
42
43/**
44 * @hide used in java.nio.
45 */
46public class PlainSocketImpl extends SocketImpl {
47
48    // For SOCKS support. A SOCKS bind() uses the last
49    // host connected to in its request.
50    private static InetAddress lastConnectedAddress;
51
52    private static int lastConnectedPort;
53
54    private boolean streaming = true;
55
56    private boolean shutdownInput;
57
58    private Proxy proxy;
59
60    private final CloseGuard guard = CloseGuard.get();
61
62    public PlainSocketImpl(FileDescriptor fd) {
63        this.fd = fd;
64        if (fd.valid()) {
65            guard.open("close");
66        }
67    }
68
69    public PlainSocketImpl(Proxy proxy) {
70        this(new FileDescriptor());
71        this.proxy = proxy;
72    }
73
74    public PlainSocketImpl() {
75        this(new FileDescriptor());
76    }
77
78    public PlainSocketImpl(FileDescriptor fd, int localport, InetAddress addr, int port) {
79        this.fd = fd;
80        this.localport = localport;
81        this.address = addr;
82        this.port = port;
83        if (fd.valid()) {
84            guard.open("close");
85        }
86    }
87
88    @Override
89    protected void accept(SocketImpl newImpl) throws IOException {
90        if (usingSocks()) {
91            ((PlainSocketImpl) newImpl).socksBind();
92            ((PlainSocketImpl) newImpl).socksAccept();
93            return;
94        }
95
96        try {
97            InetSocketAddress peerAddress = new InetSocketAddress();
98            FileDescriptor clientFd = Libcore.os.accept(fd, peerAddress);
99
100            // TODO: we can't just set newImpl.fd to clientFd because a nio SocketChannel may
101            // be sharing the FileDescriptor. http://b//4452981.
102            newImpl.fd.setInt$(clientFd.getInt$());
103
104            newImpl.address = peerAddress.getAddress();
105            newImpl.port = peerAddress.getPort();
106        } catch (ErrnoException errnoException) {
107            if (errnoException.errno == EAGAIN) {
108                throw new SocketTimeoutException(errnoException);
109            }
110            throw errnoException.rethrowAsSocketException();
111        }
112
113        // Reset the client's inherited read timeout to the Java-specified default of 0.
114        newImpl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(0));
115
116        newImpl.localport = IoBridge.getSocketLocalPort(newImpl.fd);
117    }
118
119    private boolean usingSocks() {
120        return proxy != null && proxy.type() == Proxy.Type.SOCKS;
121    }
122
123    public void initLocalPort(int localPort) {
124        this.localport = localPort;
125    }
126
127    public void initRemoteAddressAndPort(InetAddress remoteAddress, int remotePort) {
128        this.address = remoteAddress;
129        this.port = remotePort;
130    }
131
132    private void checkNotClosed() throws IOException {
133        if (!fd.valid()) {
134            throw new SocketException("Socket is closed");
135        }
136    }
137
138    @Override
139    protected synchronized int available() throws IOException {
140        checkNotClosed();
141        // we need to check if the input has been shutdown. If so
142        // we should return that there is no data to be read
143        if (shutdownInput) {
144            return 0;
145        }
146        return IoBridge.available(fd);
147    }
148
149    @Override protected void bind(InetAddress address, int port) throws IOException {
150        IoBridge.bind(fd, address, port);
151        this.address = address;
152        if (port != 0) {
153            this.localport = port;
154        } else {
155            this.localport = IoBridge.getSocketLocalPort(fd);
156        }
157    }
158
159    @Override
160    protected synchronized void close() throws IOException {
161        guard.close();
162        IoBridge.closeSocket(fd);
163    }
164
165    @Override
166    protected void connect(String aHost, int aPort) throws IOException {
167        connect(InetAddress.getByName(aHost), aPort);
168    }
169
170    @Override
171    protected void connect(InetAddress anAddr, int aPort) throws IOException {
172        connect(anAddr, aPort, 0);
173    }
174
175    /**
176     * Connects this socket to the specified remote host address/port.
177     *
178     * @param anAddr
179     *            the remote host address to connect to
180     * @param aPort
181     *            the remote port to connect to
182     * @param timeout
183     *            a timeout where supported. 0 means no timeout
184     * @throws IOException
185     *             if an error occurs while connecting
186     */
187    private void connect(InetAddress anAddr, int aPort, int timeout) throws IOException {
188        InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress.getLocalHost() : anAddr;
189        if (streaming && usingSocks()) {
190            socksConnect(anAddr, aPort, 0);
191        } else {
192            IoBridge.connect(fd, normalAddr, aPort, timeout);
193        }
194        super.address = normalAddr;
195        super.port = aPort;
196    }
197
198    @Override
199    protected void create(boolean streaming) throws IOException {
200        this.streaming = streaming;
201        this.fd = IoBridge.socket(streaming);
202    }
203
204    @Override protected void finalize() throws Throwable {
205        try {
206            if (guard != null) {
207                guard.warnIfOpen();
208            }
209            close();
210        } finally {
211            super.finalize();
212        }
213    }
214
215    @Override protected synchronized InputStream getInputStream() throws IOException {
216        checkNotClosed();
217        return new PlainSocketInputStream(this);
218    }
219
220    private static class PlainSocketInputStream extends InputStream {
221        private final PlainSocketImpl socketImpl;
222
223        public PlainSocketInputStream(PlainSocketImpl socketImpl) {
224            this.socketImpl = socketImpl;
225        }
226
227        @Override public int available() throws IOException {
228            return socketImpl.available();
229        }
230
231        @Override public void close() throws IOException {
232            socketImpl.close();
233        }
234
235        @Override public int read() throws IOException {
236            return Streams.readSingleByte(this);
237        }
238
239        @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
240            return socketImpl.read(buffer, byteOffset, byteCount);
241        }
242    }
243
244    @Override public Object getOption(int option) throws SocketException {
245        return IoBridge.getSocketOption(fd, option);
246    }
247
248    @Override protected synchronized OutputStream getOutputStream() throws IOException {
249        checkNotClosed();
250        return new PlainSocketOutputStream(this);
251    }
252
253    private static class PlainSocketOutputStream extends OutputStream {
254        private final PlainSocketImpl socketImpl;
255
256        public PlainSocketOutputStream(PlainSocketImpl socketImpl) {
257            this.socketImpl = socketImpl;
258        }
259
260        @Override public void close() throws IOException {
261            socketImpl.close();
262        }
263
264        @Override public void write(int oneByte) throws IOException {
265            Streams.writeSingleByte(this, oneByte);
266        }
267
268        @Override public void write(byte[] buffer, int offset, int byteCount) throws IOException {
269            socketImpl.write(buffer, offset, byteCount);
270        }
271    }
272
273    @Override
274    protected void listen(int backlog) throws IOException {
275        if (usingSocks()) {
276            // Do nothing for a SOCKS connection. The listen occurs on the
277            // server during the bind.
278            return;
279        }
280        try {
281            Libcore.os.listen(fd, backlog);
282        } catch (ErrnoException errnoException) {
283            throw errnoException.rethrowAsSocketException();
284        }
285    }
286
287    @Override
288    public void setOption(int option, Object value) throws SocketException {
289        IoBridge.setSocketOption(fd, option, value);
290    }
291
292    /**
293     * Gets the SOCKS proxy server port.
294     */
295    private int socksGetServerPort() {
296        // get socks server port from proxy. It is unnecessary to check
297        // "socksProxyPort" property, since proxy setting should only be
298        // determined by ProxySelector.
299        InetSocketAddress addr = (InetSocketAddress) proxy.address();
300        return addr.getPort();
301    }
302
303    /**
304     * Gets the InetAddress of the SOCKS proxy server.
305     */
306    private InetAddress socksGetServerAddress() throws UnknownHostException {
307        String proxyName;
308        // get socks server address from proxy. It is unnecessary to check
309        // "socksProxyHost" property, since all proxy setting should be
310        // determined by ProxySelector.
311        InetSocketAddress addr = (InetSocketAddress) proxy.address();
312        proxyName = addr.getHostName();
313        if (proxyName == null) {
314            proxyName = addr.getAddress().getHostAddress();
315        }
316        return InetAddress.getByName(proxyName);
317    }
318
319    /**
320     * Connect using a SOCKS server.
321     */
322    private void socksConnect(InetAddress applicationServerAddress, int applicationServerPort, int timeout) throws IOException {
323        try {
324            IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort(), timeout);
325        } catch (Exception e) {
326            throw new SocketException("SOCKS connection failed", e);
327        }
328
329        socksRequestConnection(applicationServerAddress, applicationServerPort);
330
331        lastConnectedAddress = applicationServerAddress;
332        lastConnectedPort = applicationServerPort;
333    }
334
335    /**
336     * Request a SOCKS connection to the application server given. If the
337     * request fails to complete successfully, an exception is thrown.
338     */
339    private void socksRequestConnection(InetAddress applicationServerAddress,
340            int applicationServerPort) throws IOException {
341        socksSendRequest(Socks4Message.COMMAND_CONNECT,
342                applicationServerAddress, applicationServerPort);
343        Socks4Message reply = socksReadReply();
344        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
345            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
346        }
347    }
348
349    /**
350     * Perform an accept for a SOCKS bind.
351     */
352    public void socksAccept() throws IOException {
353        Socks4Message reply = socksReadReply();
354        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
355            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
356        }
357    }
358
359    /**
360     * Shutdown the input portion of the socket.
361     */
362    @Override
363    protected void shutdownInput() throws IOException {
364        shutdownInput = true;
365        try {
366            Libcore.os.shutdown(fd, SHUT_RD);
367        } catch (ErrnoException errnoException) {
368            throw errnoException.rethrowAsSocketException();
369        }
370    }
371
372    /**
373     * Shutdown the output portion of the socket.
374     */
375    @Override
376    protected void shutdownOutput() throws IOException {
377        try {
378            Libcore.os.shutdown(fd, SHUT_WR);
379        } catch (ErrnoException errnoException) {
380            throw errnoException.rethrowAsSocketException();
381        }
382    }
383
384    /**
385     * Bind using a SOCKS server.
386     */
387    private void socksBind() throws IOException {
388        try {
389            IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort());
390        } catch (Exception e) {
391            throw new IOException("Unable to connect to SOCKS server", e);
392        }
393
394        // There must be a connection to an application host for the bind to work.
395        if (lastConnectedAddress == null) {
396            throw new SocketException("Invalid SOCKS client");
397        }
398
399        // Use the last connected address and port in the bind request.
400        socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress,
401                lastConnectedPort);
402        Socks4Message reply = socksReadReply();
403
404        if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) {
405            throw new IOException(reply.getErrorString(reply.getCommandOrResult()));
406        }
407
408        // A peculiarity of socks 4 - if the address returned is 0, use the
409        // original socks server address.
410        if (reply.getIP() == 0) {
411            address = socksGetServerAddress();
412        } else {
413            // IPv6 support not yet required as
414            // currently the Socks4Message.getIP() only returns int,
415            // so only works with IPv4 4byte addresses
416            byte[] replyBytes = new byte[4];
417            Memory.pokeInt(replyBytes, 0, reply.getIP(), ByteOrder.BIG_ENDIAN);
418            address = InetAddress.getByAddress(replyBytes);
419        }
420        localport = reply.getPort();
421    }
422
423    /**
424     * Send a SOCKS V4 request.
425     */
426    private void socksSendRequest(int command, InetAddress address, int port) throws IOException {
427        Socks4Message request = new Socks4Message();
428        request.setCommandOrResult(command);
429        request.setPort(port);
430        request.setIP(address.getAddress());
431        request.setUserId("default");
432
433        getOutputStream().write(request.getBytes(), 0, request.getLength());
434    }
435
436    /**
437     * Read a SOCKS V4 reply.
438     */
439    private Socks4Message socksReadReply() throws IOException {
440        Socks4Message reply = new Socks4Message();
441        int bytesRead = 0;
442        while (bytesRead < Socks4Message.REPLY_LENGTH) {
443            int count = getInputStream().read(reply.getBytes(), bytesRead,
444                    Socks4Message.REPLY_LENGTH - bytesRead);
445            if (count == -1) {
446                break;
447            }
448            bytesRead += count;
449        }
450        if (Socks4Message.REPLY_LENGTH != bytesRead) {
451            throw new SocketException("Malformed reply from SOCKS server");
452        }
453        return reply;
454    }
455
456    @Override
457    protected void connect(SocketAddress remoteAddr, int timeout) throws IOException {
458        InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr;
459        connect(inetAddr.getAddress(), inetAddr.getPort(), timeout);
460    }
461
462    @Override
463    protected boolean supportsUrgentData() {
464        return true;
465    }
466
467    @Override
468    protected void sendUrgentData(int value) throws IOException {
469        try {
470            byte[] buffer = new byte[] { (byte) value };
471            Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0);
472        } catch (ErrnoException errnoException) {
473            throw errnoException.rethrowAsSocketException();
474        }
475    }
476
477    /**
478     * For PlainSocketInputStream.
479     */
480    private int read(byte[] buffer, int offset, int byteCount) throws IOException {
481        if (byteCount == 0) {
482            return 0;
483        }
484        Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
485        if (shutdownInput) {
486            return -1;
487        }
488        int readCount = IoBridge.recvfrom(true, fd, buffer, offset, byteCount, 0, null, false);
489        // Return of zero bytes for a blocking socket means a timeout occurred
490        if (readCount == 0) {
491            throw new SocketTimeoutException();
492        }
493        // Return of -1 indicates the peer was closed
494        if (readCount == -1) {
495            shutdownInput = true;
496        }
497        return readCount;
498    }
499
500    /**
501     * For PlainSocketOutputStream.
502     */
503    private void write(byte[] buffer, int offset, int byteCount) throws IOException {
504        Arrays.checkOffsetAndCount(buffer.length, offset, byteCount);
505        if (streaming) {
506            while (byteCount > 0) {
507                int bytesWritten = IoBridge.sendto(fd, buffer, offset, byteCount, 0, null, 0);
508                byteCount -= bytesWritten;
509                offset += bytesWritten;
510            }
511        } else {
512            // Unlike writes to a streaming socket, writes to a datagram
513            // socket are all-or-nothing, so we don't need a loop here.
514            // http://code.google.com/p/android/issues/detail?id=15304
515            IoBridge.sendto(fd, buffer, offset, byteCount, 0, address, port);
516        }
517    }
518}
519