1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 2000, 2015, 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 
27 package sun.nio.ch;
28 
29 import java.io.*;
30 import java.net.*;
31 import java.nio.*;
32 import java.nio.channels.*;
33 import java.security.AccessController;
34 import java.security.PrivilegedExceptionAction;
35 
36 
37 // Make a socket channel look like a socket.
38 //
39 // The only aspects of java.net.Socket-hood that we don't attempt to emulate
40 // here are the interrupted-I/O exceptions (which our Solaris implementations
41 // attempt to support) and the sending of urgent data.  Otherwise an adapted
42 // socket should look enough like a real java.net.Socket to fool most of the
43 // developers most of the time, right down to the exception message strings.
44 //
45 // The methods in this class are defined in exactly the same order as in
46 // java.net.Socket so as to simplify tracking future changes to that class.
47 //
48 
49 public class SocketAdaptor
50     extends Socket
51 {
52 
53     // The channel being adapted
54     private final SocketChannelImpl sc;
55 
56     // Timeout "option" value for reads
57     private volatile int timeout = 0;
58 
SocketAdaptor(SocketChannelImpl sc)59     private SocketAdaptor(SocketChannelImpl sc) throws SocketException {
60         super(new FileDescriptorHolderSocketImpl(sc.getFD()));
61         this.sc = sc;
62     }
63 
create(SocketChannelImpl sc)64     public static Socket create(SocketChannelImpl sc) {
65         try {
66             return new SocketAdaptor(sc);
67         } catch (SocketException e) {
68             throw new InternalError("Should not reach here");
69         }
70     }
71 
getChannel()72     public SocketChannel getChannel() {
73         return sc;
74     }
75 
76     // Override this method just to protect against changes in the superclass
77     //
connect(SocketAddress remote)78     public void connect(SocketAddress remote) throws IOException {
79         connect(remote, 0);
80     }
81 
connect(SocketAddress remote, int timeout)82     public void connect(SocketAddress remote, int timeout) throws IOException {
83         if (remote == null)
84             throw new IllegalArgumentException("connect: The address can't be null");
85         if (timeout < 0)
86             throw new IllegalArgumentException("connect: timeout can't be negative");
87 
88         synchronized (sc.blockingLock()) {
89             if (!sc.isBlocking())
90                 throw new IllegalBlockingModeException();
91 
92             try {
93 
94                 if (timeout == 0) {
95                     // Android-changed: Be consistent
96                     try {
97                         sc.connect(remote);
98                     } catch (Exception ex) {
99                         Net.translateException(ex);
100                     }
101 
102                     return;
103                 }
104 
105                 sc.configureBlocking(false);
106                 try {
107                     if (sc.connect(remote))
108                         return;
109                     long to = timeout;
110                     for (;;) {
111                         if (!sc.isOpen())
112                             throw new ClosedChannelException();
113                         long st = System.currentTimeMillis();
114 
115                         int result = sc.poll(Net.POLLCONN, to);
116                         if (result > 0 && sc.finishConnect())
117                             break;
118                         to -= System.currentTimeMillis() - st;
119                         if (to <= 0) {
120                             try {
121                                 sc.close();
122                             } catch (IOException x) { }
123                             throw new SocketTimeoutException();
124                         }
125                     }
126                 } finally {
127                     if (sc.isOpen())
128                         sc.configureBlocking(true);
129                 }
130 
131             } catch (Exception x) {
132                 Net.translateException(x, true);
133             }
134         }
135 
136     }
137 
bind(SocketAddress local)138     public void bind(SocketAddress local) throws IOException {
139         try {
140             sc.bind(local);
141         } catch (Exception x) {
142             Net.translateException(x);
143         }
144     }
145 
getInetAddress()146     public InetAddress getInetAddress() {
147         // Use #remoteAddress and do manual isConnected check. #getRemoteAddress() returns
148         // non-null result before connection.
149         if (!isConnected()) {
150             return null;
151         }
152         SocketAddress remote = sc.remoteAddress();
153         if (remote == null) {
154             return null;
155         } else {
156             return ((InetSocketAddress)remote).getAddress();
157         }
158     }
159 
getLocalAddress()160     public InetAddress getLocalAddress() {
161         if (sc.isOpen()) {
162             InetSocketAddress local = sc.localAddress();
163             if (local != null) {
164                 return Net.getRevealedLocalAddress(local).getAddress();
165             }
166         }
167         return new InetSocketAddress(0).getAddress();
168     }
169 
getPort()170     public int getPort() {
171         // Use #remoteAddress and do manual isConnected check. #getRemoteAddress() returns
172         // non-null result before connection.
173         if (!isConnected()) {
174           return 0;
175         }
176         SocketAddress remote = sc.remoteAddress();
177         if (remote == null) {
178             return 0;
179         } else {
180             return ((InetSocketAddress)remote).getPort();
181         }
182     }
183 
getLocalPort()184     public int getLocalPort() {
185         SocketAddress local = sc.localAddress();
186         if (local == null) {
187             return -1;
188         } else {
189             return ((InetSocketAddress)local).getPort();
190         }
191     }
192 
193     private class SocketInputStream
194         extends ChannelInputStream
195     {
SocketInputStream()196         private SocketInputStream() {
197             super(sc);
198         }
199 
read(ByteBuffer bb)200         protected int read(ByteBuffer bb)
201             throws IOException
202         {
203             synchronized (sc.blockingLock()) {
204                 if (!sc.isBlocking())
205                     throw new IllegalBlockingModeException();
206                 if (timeout == 0)
207                     return sc.read(bb);
208                 sc.configureBlocking(false);
209 
210                 try {
211                     int n;
212                     if ((n = sc.read(bb)) != 0)
213                         return n;
214                     long to = timeout;
215                     for (;;) {
216                         if (!sc.isOpen())
217                             throw new ClosedChannelException();
218                         long st = System.currentTimeMillis();
219                         int result = sc.poll(Net.POLLIN, to);
220                         if (result > 0) {
221                             if ((n = sc.read(bb)) != 0)
222                                 return n;
223                         }
224                         to -= System.currentTimeMillis() - st;
225                         if (to <= 0)
226                             throw new SocketTimeoutException();
227                     }
228                 } finally {
229                     if (sc.isOpen())
230                         sc.configureBlocking(true);
231                 }
232 
233             }
234         }
235     }
236 
237     private InputStream socketInputStream = null;
238 
getInputStream()239     public InputStream getInputStream() throws IOException {
240         if (!sc.isOpen())
241             throw new SocketException("Socket is closed");
242         if (!sc.isConnected())
243             throw new SocketException("Socket is not connected");
244         if (!sc.isInputOpen())
245             throw new SocketException("Socket input is shutdown");
246         if (socketInputStream == null) {
247             try {
248                 socketInputStream = AccessController.doPrivileged(
249                     new PrivilegedExceptionAction<InputStream>() {
250                         public InputStream run() throws IOException {
251                             return new SocketInputStream();
252                         }
253                     });
254             } catch (java.security.PrivilegedActionException e) {
255                 throw (IOException)e.getException();
256             }
257         }
258         return socketInputStream;
259     }
260 
getOutputStream()261     public OutputStream getOutputStream() throws IOException {
262         if (!sc.isOpen())
263             throw new SocketException("Socket is closed");
264         if (!sc.isConnected())
265             throw new SocketException("Socket is not connected");
266         if (!sc.isOutputOpen())
267             throw new SocketException("Socket output is shutdown");
268         OutputStream os = null;
269         try {
270             os = AccessController.doPrivileged(
271                 new PrivilegedExceptionAction<OutputStream>() {
272                     public OutputStream run() throws IOException {
273                         return Channels.newOutputStream(sc);
274                     }
275                 });
276         } catch (java.security.PrivilegedActionException e) {
277             throw (IOException)e.getException();
278         }
279         return os;
280     }
281 
setBooleanOption(SocketOption<Boolean> name, boolean value)282     private void setBooleanOption(SocketOption<Boolean> name, boolean value)
283         throws SocketException
284     {
285         try {
286             sc.setOption(name, value);
287         } catch (IOException x) {
288             Net.translateToSocketException(x);
289         }
290     }
291 
setIntOption(SocketOption<Integer> name, int value)292     private void setIntOption(SocketOption<Integer> name, int value)
293         throws SocketException
294     {
295         try {
296             sc.setOption(name, value);
297         } catch (IOException x) {
298             Net.translateToSocketException(x);
299         }
300     }
301 
getBooleanOption(SocketOption<Boolean> name)302     private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
303         try {
304             return sc.getOption(name).booleanValue();
305         } catch (IOException x) {
306             Net.translateToSocketException(x);
307             return false;       // keep compiler happy
308         }
309     }
310 
getIntOption(SocketOption<Integer> name)311     private int getIntOption(SocketOption<Integer> name) throws SocketException {
312         try {
313             return sc.getOption(name).intValue();
314         } catch (IOException x) {
315             Net.translateToSocketException(x);
316             return -1;          // keep compiler happy
317         }
318     }
319 
setTcpNoDelay(boolean on)320     public void setTcpNoDelay(boolean on) throws SocketException {
321         setBooleanOption(StandardSocketOptions.TCP_NODELAY, on);
322     }
323 
getTcpNoDelay()324     public boolean getTcpNoDelay() throws SocketException {
325         return getBooleanOption(StandardSocketOptions.TCP_NODELAY);
326     }
327 
setSoLinger(boolean on, int linger)328     public void setSoLinger(boolean on, int linger) throws SocketException {
329         if (!on)
330             linger = -1;
331         setIntOption(StandardSocketOptions.SO_LINGER, linger);
332     }
333 
getSoLinger()334     public int getSoLinger() throws SocketException {
335         return getIntOption(StandardSocketOptions.SO_LINGER);
336     }
337 
sendUrgentData(int data)338     public void sendUrgentData(int data) throws IOException {
339         int n = sc.sendOutOfBandData((byte) data);
340         if (n == 0)
341             throw new IOException("Socket buffer full");
342     }
343 
setOOBInline(boolean on)344     public void setOOBInline(boolean on) throws SocketException {
345         setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on);
346     }
347 
getOOBInline()348     public boolean getOOBInline() throws SocketException {
349         return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE);
350     }
351 
setSoTimeout(int timeout)352     public void setSoTimeout(int timeout) throws SocketException {
353         if (timeout < 0)
354             throw new IllegalArgumentException("timeout can't be negative");
355         this.timeout = timeout;
356     }
357 
getSoTimeout()358     public int getSoTimeout() throws SocketException {
359         return timeout;
360     }
361 
setSendBufferSize(int size)362     public void setSendBufferSize(int size) throws SocketException {
363         // size 0 valid for SocketChannel, invalid for Socket
364         if (size <= 0)
365             throw new IllegalArgumentException("Invalid send size");
366         setIntOption(StandardSocketOptions.SO_SNDBUF, size);
367     }
368 
getSendBufferSize()369     public int getSendBufferSize() throws SocketException {
370         return getIntOption(StandardSocketOptions.SO_SNDBUF);
371     }
372 
setReceiveBufferSize(int size)373     public void setReceiveBufferSize(int size) throws SocketException {
374         // size 0 valid for SocketChannel, invalid for Socket
375         if (size <= 0)
376             throw new IllegalArgumentException("Invalid receive size");
377         setIntOption(StandardSocketOptions.SO_RCVBUF, size);
378     }
379 
getReceiveBufferSize()380     public int getReceiveBufferSize() throws SocketException {
381         return getIntOption(StandardSocketOptions.SO_RCVBUF);
382     }
383 
setKeepAlive(boolean on)384     public void setKeepAlive(boolean on) throws SocketException {
385         setBooleanOption(StandardSocketOptions.SO_KEEPALIVE, on);
386     }
387 
getKeepAlive()388     public boolean getKeepAlive() throws SocketException {
389         return getBooleanOption(StandardSocketOptions.SO_KEEPALIVE);
390     }
391 
setTrafficClass(int tc)392     public void setTrafficClass(int tc) throws SocketException {
393         setIntOption(StandardSocketOptions.IP_TOS, tc);
394     }
395 
getTrafficClass()396     public int getTrafficClass() throws SocketException {
397         return getIntOption(StandardSocketOptions.IP_TOS);
398     }
399 
setReuseAddress(boolean on)400     public void setReuseAddress(boolean on) throws SocketException {
401         setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
402     }
403 
getReuseAddress()404     public boolean getReuseAddress() throws SocketException {
405         return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
406     }
407 
close()408     public void close() throws IOException {
409         sc.close();
410     }
411 
shutdownInput()412     public void shutdownInput() throws IOException {
413         try {
414             sc.shutdownInput();
415         } catch (Exception x) {
416             Net.translateException(x);
417         }
418     }
419 
shutdownOutput()420     public void shutdownOutput() throws IOException {
421         try {
422             sc.shutdownOutput();
423         } catch (Exception x) {
424             Net.translateException(x);
425         }
426     }
427 
toString()428     public String toString() {
429         if (sc.isConnected())
430             return "Socket[addr=" + getInetAddress() +
431                 ",port=" + getPort() +
432                 ",localport=" + getLocalPort() + "]";
433         return "Socket[unconnected]";
434     }
435 
isConnected()436     public boolean isConnected() {
437         return sc.isConnected();
438     }
439 
isBound()440     public boolean isBound() {
441         return sc.localAddress() != null;
442     }
443 
isClosed()444     public boolean isClosed() {
445         return !sc.isOpen();
446     }
447 
isInputShutdown()448     public boolean isInputShutdown() {
449         return !sc.isInputOpen();
450     }
451 
isOutputShutdown()452     public boolean isOutputShutdown() {
453         return !sc.isOutputOpen();
454     }
455 
456     /*
457      * Android-added: for testing and internal use.
458      */
459     @Override
getFileDescriptor$()460     public FileDescriptor getFileDescriptor$() {
461         return sc.getFD();
462     }
463 }
464