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