KServerSocket.kt

package org.knio.core.net

import org.knio.core.lang.KAutoCloseable
import java.io.IOException
import java.net.InetAddress
import java.net.SocketAddress
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.SocketOptions.*

/**
 * This class implements server sockets. A server socket waits for requests to come in over the network. It performs
 * some operation based on that request, and then possibly returns a result to the requester.
 *
 * @see java.net.ServerSocket
 * @see java.nio.channels.AsynchronousServerSocketChannel
 */
interface KServerSocket: KAutoCloseable {

    /**
     * Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made.
     *
     * A new Socket s is created and, if there is a security manager, the security manager's checkAccept method is
     * called with s.getInetAddress().getHostAddress() and s.getPort() as its arguments to ensure the operation is
     * allowed. This could result in a SecurityException.
     *
     * @return the new Socket
     *
     * @throws IOException if an I/O error occurs when waiting for a connection.
     * @throws SecurityException if a security manager exists and its checkAccept method doesn't allow the operation.
     * @throws SocketTimeoutException if a timeout was previously set with setSoTimeout and the timeout has beenreached.
     *
     * @see java.net.ServerSocket.accept
     * @see java.nio.channels.AsynchronousServerSocketChannel.accept
     */
    @Throws(IOException::class, SecurityException::class, SocketTimeoutException::class)
    suspend fun accept(): KSocket

    /**
     * Binds the ServerSocket to a specific address (IP address and port number).
     *
     * If the address is null, then the system will pick up an ephemeral port and a valid local address to bind the
     * socket.
     *
     * The backlog argument is the requested maximum number of pending connections on the socket. Its exact semantics
     * are implementation specific. In particular, an implementation may impose a maximum length or may choose to ignore
     * the parameter altogther. The value provided should be greater than 0. If it is less than or equal to 0, then an
     * implementation specific default will be used.
     *
     * @param endpoint The IP address and port number to bind to.
     * @param backlog The maximum number of pending connections.
     *
     * @throws IOException if an I/O error occurs when binding the socket.
     * @throws IllegalArgumentException if endpoint is a SocketAddress subclass not supported by this socket.
     * @throws SecurityException if a security manager exists and its checkListen method doesn't allow the operation.
     *
     * @see java.net.ServerSocket.bind
     * @see java.nio.channels.AsynchronousServerSocketChannel.bind
     */
    @Throws(IOException::class, IllegalArgumentException::class, SecurityException::class)
    suspend fun bind(endpoint: SocketAddress, backlog: Int = 0)

    /**
     * Closes this socket. Any thread currently blocked in accept() will throw a SocketException.
     *
     * If this socket has an associated channel then the channel is closed as well.
     *
     * @throws IOException if an I/O error occurs when closing the socket.
     *
     * @see java.net.ServerSocket.close
     * @see java.nio.channels.AsynchronousServerSocketChannel.close
     */
    @Throws(IOException::class)
    override suspend fun close()

    /**
     * Returns the local address of this server socket.
     *
     * If the socket was bound prior to being closed, then this method will continue to return the local address after
     * the socket is closed.
     *
     * If there is a security manager set, its checkConnect method is called with the local address and -1 as its
     * arguments to see if the operation is allowed. If the operation is not allowed, the loopback address is returned.
     *
     * @return the address to which this socket is bound, or the loopback address if denied by the security manager, or
     * `null` if the socket is unbound.
     *
     * @see java.net.ServerSocket.getInetAddress
     * @see java.nio.channels.AsynchronousServerSocketChannel.getLocalAddress
     */
    suspend fun getInetAddress(): InetAddress?

    /**
     * Returns the port number on which this socket is listening.
     *
     * If the socket was bound prior to being closed, then this method will continue to return the port number after the
     * socket is closed.
     *
     * @return the port number to which this socket is listening, or -1 if the socket is unbound.
     *
     * @see java.net.ServerSocket.getLocalPort
     * @see java.nio.channels.AsynchronousServerSocketChannel.getLocalAddress
     */
    suspend fun getLocalPort(): Int

    /**
     * Returns the address of the endpoint this socket is bound to.
     *
     * If the socket was bound prior to being closed, then this method will continue to return the address of the
     * endpoint after the socket is closed.
     *
     * If there is a security manager set, its checkConnect method is called with the local address and -1 as its
     * arguments to see if the operation is allowed. If the operation is not allowed, a SocketAddress representing the
     * loopback address and the local port to which the socket is bound is returned.
     *
     * @return a SocketAddress representing the local endpoint of this socket, or a SocketAddress representing the
     * loopback address if denied by the security manager, or `null` if the socket is not bound yet.
     *
     * @see java.net.ServerSocket.getLocalSocketAddress
     * @see java.nio.channels.AsynchronousServerSocketChannel.getLocalAddress
     */
    suspend fun getLocalSocketAddress(): SocketAddress?

    /**
     * Enable/disable the [SO_REUSEADDR] socket option.
     *
     * When a TCP connection is closed the connection may remain in a timeout state for a period of time after the
     * connection is closed (typically known as the TIME_WAIT state or 2MSL wait state). For applications using a well
     * known socket address or port it may not be possible to bind a socket to the required SocketAddress if there is a
     * connection in the timeout state involving the socket address or port.
     *
     * Enabling SO_REUSEADDR prior to binding the socket using bind(SocketAddress) allows the socket to be bound even
     * though a previous connection is in a timeout state.
     *
     * When a ServerSocket is created the initial setting of [SO_REUSEADDR] is not defined. Applications can use
     * getReuseAddress() to determine the initial setting of [SO_REUSEADDR].
     *
     * The behaviour when SO_REUSEADDR is enabled or disabled after a socket is bound (See isBound()) is not defined.
     *
     * @param on `true` to enable [SO_REUSEADDR], `false` to disable.
     *
     * @throws SocketException if an I/O error occurs when setting the option.
     *
     * @see java.net.ServerSocket.setReuseAddress
     * @see java.nio.channels.AsynchronousServerSocketChannel.setOption
     * @see SO_REUSEADDR
     */
    @Throws(SocketException::class)
    suspend fun setReuseAddress(on: Boolean)

    /**
     * Tests if [SO_REUSEADDR] is enabled.
     *
     * @return `true` if [SO_REUSEADDR] is enabled, `false` if it is disabled.
     *
     * @throws SocketException if an I/O error occurs when getting the option.
     *
     * @see java.net.ServerSocket.getReuseAddress
     * @see java.nio.channels.AsynchronousServerSocketChannel.setOption
     * @see SO_REUSEADDR
     */
    @Throws(SocketException::class)
    suspend fun getReuseAddress(): Boolean

    /**
     * Sets a default proposed value for the [SO_RCVBUF] option for sockets accepted from this ServerSocket. The value
     * actually set in the accepted socket must be determined by calling [KSocket.getReceiveBufferSize] after the
     * socket is returned by [accept].
     *
     * The value of [SO_RCVBUF] is used both to set the size of the internal socket receive buffer, and to set the size
     * of the TCP receive window that is advertized to the remote peer.
     *
     * It is possible to change the value subsequently, by calling [KSocket.setReceiveBufferSize]. However, if the
     * application wishes to allow a receive window larger than 64K bytes, as defined by RFC1323 then the proposed value
     * must be set in the ServerSocket before it is bound to a local address. This implies, that the ServerSocket must
     * be created with the no-argument constructor, then [setReceiveBufferSize] must be called and lastly the
     * [KServerSocket] is bound to an address by calling [bind].
     *
     * Failure to do this will not cause an error, and the buffer size may be set to the requested value but the TCP
     * receive window in sockets accepted from this ServerSocket will be no larger than 64K bytes.
     *
     * @param size the size to which to set the receive buffer size. This value must be greater than 0.
     *
     * @throws SocketException if an I/O error occurs when setting the option.
     *
     * @see java.net.ServerSocket.setReceiveBufferSize
     * @see java.nio.channels.AsynchronousServerSocketChannel.setOption
     * @see SO_RCVBUF
     */
    @Throws(SocketException::class)
    suspend fun setReceiveBufferSize(size: Int)


    /**
     * Gets the value of the [SO_RCVBUF] option for this ServerSocket, that is the proposed buffer size that will be
     * used for [KSocket]s accepted from this [KServerSocket].
     *
     * Note, the value actually set in the accepted socket is determined by calling [KSocket.getReceiveBufferSize].
     *
     * @return the value of the [SO_RCVBUF] option for this [KServerSocket].
     *
     * @throws SocketException if an I/O error occurs when getting the option.
     *
     * @see java.net.ServerSocket.getReceiveBufferSize
     * @see java.nio.channels.AsynchronousServerSocketChannel.getOption
     * @see SO_RCVBUF
     */
    @Throws(SocketException::class)
    suspend fun getReceiveBufferSize(): Int

    /**
     * Returns the binding state of the [KServerSocket].
     *
     * @return `true` if the ServerSocket is bound to an address, `false` otherwise.
     *
     * @see java.net.ServerSocket.isBound
     * @see java.nio.channels.AsynchronousServerSocketChannel.getLocalAddress
     */
    suspend fun isBound(): Boolean

    /**
     * Returns the closed state of the [KServerSocket].
     *
     * @return `true` if the [KServerSocket] is closed, `false` otherwise.
     *
     * @see java.net.ServerSocket.isClosed
     * @see java.nio.channels.AsynchronousServerSocketChannel.isOpen
     */
    suspend fun isClosed(): Boolean
}