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