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