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         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 
 76     private InetSocketAddress localAddress() {
 77         return (InetSocketAddress) sc.localAddress();
 78     }
 79 
 80     private InetSocketAddress remoteAddress() {
 81         return (InetSocketAddress) sc.remoteAddress();
 82     }
 83 
 84     @Override
 85     public void connect(SocketAddress remote) throws IOException {
 86         connect(remote, 0);
 87     }
 88 
 89     @Override
 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
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
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
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
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
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
158     public SocketAddress getRemoteSocketAddress() {
159         return sc.remoteAddress();
160     }
161 
162     @Override
163     public SocketAddress getLocalSocketAddress() {
164         return Net.getRevealedLocalAddress(sc.localAddress());
165     }
166 
167     @Override
168     public SocketChannel getChannel() {
169         return sc;
170     }
171 
172     @Override
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 SocketInputStream(sc, () -> timeout);
181     }
182 
183     @Override
184     public OutputStream getOutputStream() throws IOException {
185         if (!sc.isOpen())
186             throw new SocketException("Socket is closed");
187         if (!sc.isConnected())
188             throw new SocketException("Socket is not connected");
189         if (!sc.isOutputOpen())
190             throw new SocketException("Socket output is shutdown");
191         return new SocketOutputStream(sc);
192     }
193 
194     private void setBooleanOption(SocketOption<Boolean> name, boolean value)
195         throws SocketException
196     {
197         try {
198             sc.setOption(name, value);
199         } catch (IOException x) {
200             Net.translateToSocketException(x);
201         }
202     }
203 
204     private void setIntOption(SocketOption<Integer> name, int value)
205         throws SocketException
206     {
207         try {
208             sc.setOption(name, value);
209         } catch (IOException x) {
210             Net.translateToSocketException(x);
211         }
212     }
213 
214     private boolean getBooleanOption(SocketOption<Boolean> name) throws SocketException {
215         try {
216             return sc.getOption(name).booleanValue();
217         } catch (IOException x) {
218             Net.translateToSocketException(x);
219             return false;       // keep compiler happy
220         }
221     }
222 
223     private int getIntOption(SocketOption<Integer> name) throws SocketException {
224         try {
225             return sc.getOption(name).intValue();
226         } catch (IOException x) {
227             Net.translateToSocketException(x);
228             return -1;          // keep compiler happy
229         }
230     }
231 
232     @Override
233     public void setTcpNoDelay(boolean on) throws SocketException {
234         setBooleanOption(StandardSocketOptions.TCP_NODELAY, on);
235     }
236 
237     @Override
238     public boolean getTcpNoDelay() throws SocketException {
239         return getBooleanOption(StandardSocketOptions.TCP_NODELAY);
240     }
241 
242     @Override
243     public void setSoLinger(boolean on, int linger) throws SocketException {
244         if (!on)
245             linger = -1;
246         setIntOption(StandardSocketOptions.SO_LINGER, linger);
247     }
248 
249     @Override
250     public int getSoLinger() throws SocketException {
251         return getIntOption(StandardSocketOptions.SO_LINGER);
252     }
253 
254     @Override
255     public void sendUrgentData(int data) throws IOException {
256         int n = sc.sendOutOfBandData((byte) data);
257         if (n == 0)
258             throw new IOException("Socket buffer full");
259     }
260 
261     @Override
262     public void setOOBInline(boolean on) throws SocketException {
263         setBooleanOption(ExtendedSocketOption.SO_OOBINLINE, on);
264     }
265 
266     @Override
267     public boolean getOOBInline() throws SocketException {
268         return getBooleanOption(ExtendedSocketOption.SO_OOBINLINE);
269     }
270 
271     @Override
272     public void setSoTimeout(int timeout) throws SocketException {
273         if (!sc.isOpen())
274             throw new SocketException("Socket is closed");
275         if (timeout < 0)
276             throw new IllegalArgumentException("timeout < 0");
277         this.timeout = timeout;
278     }
279 
280     @Override
281     public int getSoTimeout() throws SocketException {
282         if (!sc.isOpen())
283             throw new SocketException("Socket is closed");
284         return timeout;
285     }
286 
287     @Override
288     public void setSendBufferSize(int size) throws SocketException {
289         // size 0 valid for SocketChannel, invalid for Socket
290         if (size <= 0)
291             throw new IllegalArgumentException("Invalid send size");
292         setIntOption(StandardSocketOptions.SO_SNDBUF, size);
293     }
294 
295     @Override
296     public int getSendBufferSize() throws SocketException {
297         return getIntOption(StandardSocketOptions.SO_SNDBUF);
298     }
299 
300     @Override
301     public void setReceiveBufferSize(int size) throws SocketException {
302         // size 0 valid for SocketChannel, invalid for Socket
303         if (size <= 0)
304             throw new IllegalArgumentException("Invalid receive size");
305         setIntOption(StandardSocketOptions.SO_RCVBUF, size);
306     }
307 
308     @Override
309     public int getReceiveBufferSize() throws SocketException {
310         return getIntOption(StandardSocketOptions.SO_RCVBUF);
311     }
312 
313     @Override
314     public void setKeepAlive(boolean on) throws SocketException {
315         setBooleanOption(StandardSocketOptions.SO_KEEPALIVE, on);
316     }
317 
318     @Override
319     public boolean getKeepAlive() throws SocketException {
320         return getBooleanOption(StandardSocketOptions.SO_KEEPALIVE);
321     }
322 
323     @Override
324     public void setTrafficClass(int tc) throws SocketException {
325         setIntOption(StandardSocketOptions.IP_TOS, tc);
326     }
327 
328     @Override
329     public int getTrafficClass() throws SocketException {
330         return getIntOption(StandardSocketOptions.IP_TOS);
331     }
332 
333     @Override
334     public void setReuseAddress(boolean on) throws SocketException {
335         setBooleanOption(StandardSocketOptions.SO_REUSEADDR, on);
336     }
337 
338     @Override
339     public boolean getReuseAddress() throws SocketException {
340         return getBooleanOption(StandardSocketOptions.SO_REUSEADDR);
341     }
342 
343     @Override
344     public void close() throws IOException {
345         sc.close();
346     }
347 
348     @Override
349     public void shutdownInput() throws IOException {
350         try {
351             sc.shutdownInput();
352         } catch (Exception x) {
353             Net.translateException(x);
354         }
355     }
356 
357     @Override
358     public void shutdownOutput() throws IOException {
359         try {
360             sc.shutdownOutput();
361         } catch (Exception x) {
362             Net.translateException(x);
363         }
364     }
365 
366     @Override
367     public String toString() {
368         if (sc.isConnected())
369             return "Socket[addr=" + getInetAddress() +
370                 ",port=" + getPort() +
371                 ",localport=" + getLocalPort() + "]";
372         return "Socket[unconnected]";
373     }
374 
375     @Override
376     public boolean isConnected() {
377         return sc.isConnected();
378     }
379 
380     @Override
381     public boolean isBound() {
382         return sc.localAddress() != null;
383     }
384 
385     @Override
386     public boolean isClosed() {
387         return !sc.isOpen();
388     }
389 
390     @Override
391     public boolean isInputShutdown() {
392         return !sc.isInputOpen();
393     }
394 
395     @Override
396     public boolean isOutputShutdown() {
397         return !sc.isOutputOpen();
398     }
399 
400     @Override
401     public <T> Socket setOption(SocketOption<T> name, T value) throws IOException {
402         sc.setOption(name, value);
403         return this;
404     }
405 
406     @Override
407     public <T> T getOption(SocketOption<T> name) throws IOException {
408         return sc.getOption(name);
409     }
410 
411     @Override
412     public Set<SocketOption<?>> supportedOptions() {
413         return sc.supportedOptions();
414     }
415 }