1 /* 2 * Copyright (c) 1995, 2019, 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 java.net; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.OutputStream; 31 import java.io.FileDescriptor; 32 import java.util.Set; 33 34 import sun.net.PlatformSocketImpl; 35 36 /** 37 * The abstract class {@code SocketImpl} is a common superclass 38 * of all classes that actually implement sockets. It is used to 39 * create both client and server sockets. 40 * <p> 41 * A "plain" socket implements these methods exactly as 42 * described, without attempting to go through a firewall or proxy. 43 * 44 * @author unascribed 45 * @since 1.0 46 */ 47 public abstract class SocketImpl implements SocketOptions { 48 49 /** 50 * Creates an instance of platform's SocketImpl 51 */ 52 @SuppressWarnings("unchecked") 53 static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server) { 54 return (S) new PlainSocketImpl(server); 55 } 56 57 /** 58 * The file descriptor object for this socket. 59 */ 60 protected FileDescriptor fd; 61 62 /** 63 * The IP address of the remote end of this socket. 64 */ 65 protected InetAddress address; 66 67 /** 68 * The port number on the remote host to which this socket is connected. 69 */ 70 protected int port; 71 72 /** 73 * The local port number to which this socket is connected. 74 */ 75 protected int localport; 76 77 /** 78 * Whether this is a server or not. 79 */ 80 final boolean isServer; 81 82 83 SocketImpl(boolean isServer) { 84 this.isServer = isServer; 85 } 86 87 /** 88 * Initialize a new instance of this class 89 */ 90 public SocketImpl() { 91 this.isServer = false; 92 } 93 94 /** 95 * Creates either a stream or a datagram socket. 96 * 97 * @param stream if {@code true}, create a stream socket; 98 * otherwise, create a datagram socket. 99 * @exception IOException if an I/O error occurs while creating the 100 * socket. 101 */ 102 protected abstract void create(boolean stream) throws IOException; 103 104 /** 105 * Connects this socket to the specified port on the named host. 106 * 107 * @param host the name of the remote host. 108 * @param port the port number. 109 * @exception IOException if an I/O error occurs when connecting to the 110 * remote host. 111 */ 112 protected abstract void connect(String host, int port) throws IOException; 113 114 /** 115 * Connects this socket to the specified port number on the specified host. 116 * 117 * @param address the IP address of the remote host. 118 * @param port the port number. 119 * @exception IOException if an I/O error occurs when attempting a 120 * connection. 121 */ 122 protected abstract void connect(InetAddress address, int port) throws IOException; 123 124 /** 125 * Connects this socket to the specified port number on the specified host. 126 * A timeout of zero is interpreted as an infinite timeout. The connection 127 * will then block until established or an error occurs. 128 * 129 * @param address the Socket address of the remote host. 130 * @param timeout the timeout value, in milliseconds, or zero for no timeout. 131 * @exception IOException if an I/O error occurs when attempting a 132 * connection. 133 * @since 1.4 134 */ 135 protected abstract void connect(SocketAddress address, int timeout) throws IOException; 136 137 /** 138 * Binds this socket to the specified local IP address and port number. 139 * 140 * @param host an IP address that belongs to a local interface. 141 * @param port the port number. 142 * @exception IOException if an I/O error occurs when binding this socket. 143 */ 144 protected abstract void bind(InetAddress host, int port) throws IOException; 145 146 /** 147 * Sets the maximum queue length for incoming connection indications 148 * (a request to connect) to the {@code count} argument. If a 149 * connection indication arrives when the queue is full, the 150 * connection is refused. 151 * 152 * @param backlog the maximum length of the queue. 153 * @exception IOException if an I/O error occurs when creating the queue. 154 */ 155 protected abstract void listen(int backlog) throws IOException; 156 157 /** 158 * Accepts a connection. 159 * 160 * @param s the accepted connection. 161 * @exception IOException if an I/O error occurs when accepting the 162 * connection. 163 */ 164 protected abstract void accept(SocketImpl s) throws IOException; 165 166 /** 167 * Returns an input stream for this socket. 168 * 169 * @return a stream for reading from this socket. 170 * @exception IOException if an I/O error occurs when creating the 171 * input stream. 172 */ 173 protected abstract InputStream getInputStream() throws IOException; 174 175 /** 176 * Returns an output stream for this socket. 177 * 178 * @return an output stream for writing to this socket. 179 * @exception IOException if an I/O error occurs when creating the 180 * output stream. 181 */ 182 protected abstract OutputStream getOutputStream() throws IOException; 183 184 /** 185 * Returns the number of bytes that can be read from this socket 186 * without blocking. 187 * 188 * @return the number of bytes that can be read from this socket 189 * without blocking. 190 * @exception IOException if an I/O error occurs when determining the 191 * number of bytes available. 192 */ 193 protected abstract int available() throws IOException; 194 195 /** 196 * Closes this socket. 197 * 198 * @exception IOException if an I/O error occurs when closing this socket. 199 */ 200 protected abstract void close() throws IOException; 201 202 /** 203 * Closes this socket, ignoring any IOException that is thrown by close. 204 */ 205 void closeQuietly() { 206 try { 207 close(); 208 } catch (IOException ignore) { } 209 } 210 211 /** 212 * Places the input stream for this socket at "end of stream". 213 * Any data sent to this socket is acknowledged and then 214 * silently discarded. 215 * 216 * If you read from a socket input stream after invoking this method on the 217 * socket, the stream's {@code available} method will return 0, and its 218 * {@code read} methods will return {@code -1} (end of stream). 219 * 220 * @exception IOException if an I/O error occurs when shutting down this 221 * socket. 222 * @see java.net.Socket#shutdownOutput() 223 * @see java.net.Socket#close() 224 * @see java.net.Socket#setSoLinger(boolean, int) 225 * @since 1.3 226 */ 227 protected void shutdownInput() throws IOException { 228 throw new IOException("Method not implemented!"); 229 } 230 231 /** 232 * Disables the output stream for this socket. 233 * For a TCP socket, any previously written data will be sent 234 * followed by TCP's normal connection termination sequence. 235 * 236 * If you write to a socket output stream after invoking 237 * shutdownOutput() on the socket, the stream will throw 238 * an IOException. 239 * 240 * @exception IOException if an I/O error occurs when shutting down this 241 * socket. 242 * @see java.net.Socket#shutdownInput() 243 * @see java.net.Socket#close() 244 * @see java.net.Socket#setSoLinger(boolean, int) 245 * @since 1.3 246 */ 247 protected void shutdownOutput() throws IOException { 248 throw new IOException("Method not implemented!"); 249 } 250 251 /** 252 * Returns the value of this socket's {@code fd} field. 253 * 254 * @return the value of this socket's {@code fd} field. 255 * @see java.net.SocketImpl#fd 256 */ 257 protected FileDescriptor getFileDescriptor() { 258 return fd; 259 } 260 261 /** 262 * Returns the value of this socket's {@code address} field. 263 * 264 * @return the value of this socket's {@code address} field. 265 * @see java.net.SocketImpl#address 266 */ 267 protected InetAddress getInetAddress() { 268 return address; 269 } 270 271 /** 272 * Returns the value of this socket's {@code port} field. 273 * 274 * @return the value of this socket's {@code port} field. 275 * @see java.net.SocketImpl#port 276 */ 277 protected int getPort() { 278 return port; 279 } 280 281 /** 282 * Returns whether or not this SocketImpl supports sending 283 * urgent data. By default, false is returned 284 * unless the method is overridden in a sub-class 285 * 286 * @return true if urgent data supported 287 * @see java.net.SocketImpl#address 288 * @since 1.4 289 */ 290 protected boolean supportsUrgentData () { 291 return false; // must be overridden in sub-class 292 } 293 294 /** 295 * Send one byte of urgent data on the socket. 296 * The byte to be sent is the low eight bits of the parameter 297 * @param data The byte of data to send 298 * @exception IOException if there is an error 299 * sending the data. 300 * @since 1.4 301 */ 302 protected abstract void sendUrgentData (int data) throws IOException; 303 304 /** 305 * Returns the value of this socket's {@code localport} field. 306 * 307 * @return the value of this socket's {@code localport} field. 308 * @see java.net.SocketImpl#localport 309 */ 310 protected int getLocalPort() { 311 return localport; 312 } 313 314 /** 315 * Returns the address and port of this socket as a {@code String}. 316 * 317 * @return a string representation of this socket. 318 */ 319 public String toString() { 320 return "Socket[addr=" + getInetAddress() + 321 ",port=" + getPort() + ",localport=" + getLocalPort() + "]"; 322 } 323 324 void reset() { 325 fd = null; 326 address = null; 327 port = 0; 328 localport = 0; 329 } 330 331 /** 332 * Sets performance preferences for this socket. 333 * 334 * <p> Sockets use the TCP/IP protocol by default. Some implementations 335 * may offer alternative protocols which have different performance 336 * characteristics than TCP/IP. This method allows the application to 337 * express its own preferences as to how these tradeoffs should be made 338 * when the implementation chooses from the available protocols. 339 * 340 * <p> Performance preferences are described by three integers 341 * whose values indicate the relative importance of short connection time, 342 * low latency, and high bandwidth. The absolute values of the integers 343 * are irrelevant; in order to choose a protocol the values are simply 344 * compared, with larger values indicating stronger preferences. Negative 345 * values represent a lower priority than positive values. If the 346 * application prefers short connection time over both low latency and high 347 * bandwidth, for example, then it could invoke this method with the values 348 * {@code (1, 0, 0)}. If the application prefers high bandwidth above low 349 * latency, and low latency above short connection time, then it could 350 * invoke this method with the values {@code (0, 1, 2)}. 351 * 352 * By default, this method does nothing, unless it is overridden in 353 * a sub-class. 354 * 355 * @param connectionTime 356 * An {@code int} expressing the relative importance of a short 357 * connection time 358 * 359 * @param latency 360 * An {@code int} expressing the relative importance of low 361 * latency 362 * 363 * @param bandwidth 364 * An {@code int} expressing the relative importance of high 365 * bandwidth 366 * 367 * @since 1.5 368 */ 369 protected void setPerformancePreferences(int connectionTime, 370 int latency, 371 int bandwidth) 372 { 373 /* Not implemented yet */ 374 } 375 376 /** 377 * Called to set a socket option. 378 * 379 * @param <T> The type of the socket option value 380 * @param name The socket option 381 * 382 * @param value The value of the socket option. A value of {@code null} 383 * may be valid for some options. 384 * 385 * @throws UnsupportedOperationException if the SocketImpl does not 386 * support the option 387 * 388 * @throws IOException if an I/O error occurs, or if the socket is closed. 389 * 390 * @since 9 391 */ 392 protected <T> void setOption(SocketOption<T> name, T value) throws IOException { 393 if (name == StandardSocketOptions.SO_KEEPALIVE && !isServer) { 394 setOption(SocketOptions.SO_KEEPALIVE, value); 395 } else if (name == StandardSocketOptions.SO_SNDBUF && !isServer) { 396 setOption(SocketOptions.SO_SNDBUF, value); 397 } else if (name == StandardSocketOptions.SO_RCVBUF) { 398 setOption(SocketOptions.SO_RCVBUF, value); 399 } else if (name == StandardSocketOptions.SO_REUSEADDR) { 400 setOption(SocketOptions.SO_REUSEADDR, value); 401 } else if (name == StandardSocketOptions.SO_REUSEPORT && 402 supportedOptions().contains(name)) { 403 setOption(SocketOptions.SO_REUSEPORT, value); 404 } else if (name == StandardSocketOptions.SO_LINGER && !isServer) { 405 setOption(SocketOptions.SO_LINGER, value); 406 } else if (name == StandardSocketOptions.IP_TOS) { 407 setOption(SocketOptions.IP_TOS, value); 408 } else if (name == StandardSocketOptions.TCP_NODELAY && !isServer) { 409 setOption(SocketOptions.TCP_NODELAY, value); 410 } else { 411 throw new UnsupportedOperationException("unsupported option"); 412 } 413 } 414 415 /** 416 * Called to get a socket option. 417 * 418 * @param <T> The type of the socket option value 419 * @param name The socket option 420 * 421 * @return the value of the named option 422 * 423 * @throws UnsupportedOperationException if the SocketImpl does not 424 * support the option. 425 * 426 * @throws IOException if an I/O error occurs, or if the socket is closed. 427 * 428 * @since 9 429 */ 430 @SuppressWarnings("unchecked") 431 protected <T> T getOption(SocketOption<T> name) throws IOException { 432 if (name == StandardSocketOptions.SO_KEEPALIVE && !isServer) { 433 return (T)getOption(SocketOptions.SO_KEEPALIVE); 434 } else if (name == StandardSocketOptions.SO_SNDBUF && !isServer) { 435 return (T)getOption(SocketOptions.SO_SNDBUF); 436 } else if (name == StandardSocketOptions.SO_RCVBUF) { 437 return (T)getOption(SocketOptions.SO_RCVBUF); 438 } else if (name == StandardSocketOptions.SO_REUSEADDR) { 439 return (T)getOption(SocketOptions.SO_REUSEADDR); 440 } else if (name == StandardSocketOptions.SO_REUSEPORT && 441 supportedOptions().contains(name)) { 442 return (T)getOption(SocketOptions.SO_REUSEPORT); 443 } else if (name == StandardSocketOptions.SO_LINGER && !isServer) { 444 return (T)getOption(SocketOptions.SO_LINGER); 445 } else if (name == StandardSocketOptions.IP_TOS) { 446 return (T)getOption(SocketOptions.IP_TOS); 447 } else if (name == StandardSocketOptions.TCP_NODELAY && !isServer) { 448 return (T)getOption(SocketOptions.TCP_NODELAY); 449 } else { 450 throw new UnsupportedOperationException("unsupported option"); 451 } 452 } 453 454 /** 455 * Attempts to copy socket options from this SocketImpl to a target SocketImpl. 456 * At this time, only the SO_TIMEOUT make sense to copy. 457 */ 458 void copyOptionsTo(SocketImpl target) { 459 try { 460 Object timeout = getOption(SocketOptions.SO_TIMEOUT); 461 if (timeout instanceof Integer) { 462 target.setOption(SocketOptions.SO_TIMEOUT, timeout); 463 } 464 } catch (IOException ignore) { } 465 } 466 467 private static final Set<SocketOption<?>> socketOptions; 468 469 private static final Set<SocketOption<?>> serverSocketOptions; 470 471 static { 472 socketOptions = Set.of(StandardSocketOptions.SO_KEEPALIVE, 473 StandardSocketOptions.SO_SNDBUF, 474 StandardSocketOptions.SO_RCVBUF, 475 StandardSocketOptions.SO_REUSEADDR, 476 StandardSocketOptions.SO_LINGER, 477 StandardSocketOptions.IP_TOS, 478 StandardSocketOptions.TCP_NODELAY); 479 480 serverSocketOptions = Set.of(StandardSocketOptions.SO_RCVBUF, 481 StandardSocketOptions.SO_REUSEADDR, 482 StandardSocketOptions.IP_TOS); 483 } 484 485 /** 486 * Returns a set of SocketOptions supported by this impl 487 * and by this impl's socket (Socket or ServerSocket) 488 * 489 * @return a Set of SocketOptions 490 * 491 * @since 9 492 */ 493 protected Set<SocketOption<?>> supportedOptions() { 494 if (!isServer) { 495 return socketOptions; 496 } else { 497 return serverSocketOptions; 498 } 499 } 500 }