blob: e6dd0d0c79e91edb77db6a30ddcf2842d6cad1ad [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tuweni.net.coroutines
import java.io.IOException
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.SocketAddress
import java.net.SocketOption
import java.nio.channels.AlreadyBoundException
import java.nio.channels.ClosedChannelException
import java.nio.channels.NetworkChannel
import java.nio.channels.UnsupportedAddressTypeException
/**
* A co-routine based network channel.
*
*/
interface CoroutineNetworkChannel : NetworkChannel {
/**
* Indicates if this channel is open.
*
* @return `true` if this channel is open.
*/
override fun isOpen(): Boolean
/**
* Closes this channel.
*
* After a channel is closed, any further attempt to invoke I/O operations upon it will cause a
* [ClosedChannelException] to be thrown.
*
* @throws IOException If an I/O error occurs.
*/
override fun close()
/**
* Binds the channel's socket to a local address.
*
* This method is used to establish an association between the socket and a local address. Once an association is
* established then the socket remains bound until the channel is closed. If the `local` parameter has the value
* `null` then the socket will be bound to an address that is assigned automatically.
*
* @param local The address to bind the socket, or `null` to bind the socket to an automatically assigned socket
* address.
* @return This channel.
* @throws AlreadyBoundException If the socket is already bound.
* @throws UnsupportedAddressTypeException If the type of the given address is not supported.
* @throws ClosedChannelException If the channel is closed.
* @throws IOException If some other I/O error occurs.
* @throws SecurityException If a security manager is installed and it denies an unspecified permission. An
* implementation of this interface should specify any required permissions.
*/
override fun bind(local: SocketAddress?): CoroutineNetworkChannel
/**
* Returns the socket address that this channel's socket is bound to.
*
* @return The socket address that the socket is bound to, or `null` if the channel's socket is not bound.
* @throws ClosedChannelException If the channel is closed.
* @throws IOException If an I/O error occurs.
*/
override fun getLocalAddress(): SocketAddress?
/**
* Returns the InetAddress corresponding to the interface this channel's socket is bound to.
*
* @return The InetAddress that the socket is bound to, or `null` if the channel's socket is not bound.
* @throws IllegalStateException If the channel is not bound to an inet address
* @throws ClosedChannelException If the channel is closed.
* @throws IOException If an I/O error occurs.
*/
fun getAdvertisableAddress(): InetAddress? {
val localAddress = localAddress ?: return null
val localInetAddress = (localAddress as? InetSocketAddress)?.address
?: throw IllegalStateException("Channel bound to non-inet interface")
if (!localInetAddress.isAnyLocalAddress) {
return localInetAddress
}
// This will typically work ok on hosts with only a single interface
return InetAddress.getLocalHost()
}
/**
* The port number on the local host to which this socket is bound.
*
* The port number on the local host to which this socket is bound, -1 if the socket is closed, or 0 if it is not
* bound yet.
*/
val localPort: Int
/**
* Sets the value of a socket option.
*
* @param <T> The type of the socket option value.
* @param name The socket option.
* @param value The value of the socket option. A value of `null` may be a valid value for some socket options.
* @return This channel
* @throws UnsupportedOperationException If the socket option is not supported by this channel.
* @throws IllegalArgumentException If the value is not a valid value for this socket option.
* @throws ClosedChannelException If this channel is closed.
* @throws IOException If an I/O error occurs.
* @see java.net.StandardSocketOptions
*/
override fun <T : Any> setOption(name: SocketOption<T>, value: T?): NetworkChannel
/**
* Returns the value of a socket option.
*
* @param <T> The type of the socket option value.
* @param name The socket option.
* @return The value of the socket option. A value of `null` may be a valid value for some socket options.
* @throws UnsupportedOperationException If the socket option is not supported by this channel.
* @throws ClosedChannelException If this channel is closed.
* @throws IOException If an I/O error occurs.
* @see java.net.StandardSocketOptions
*/
override fun <T : Any> getOption(name: SocketOption<T>): T?
/**
* Returns a set of the socket options supported by this channel.
*
* @return A set of the socket options supported by this channel.
*/
override fun supportedOptions(): Set<SocketOption<*>>
}
internal class CoroutineNetworkChannelMixin(
private val channel: NetworkChannel
) : CoroutineNetworkChannel, NetworkChannel by channel {
override val localPort: Int
get() {
if (!isOpen) {
return -1
}
return (localAddress as? InetSocketAddress)?.port ?: 0
}
override fun bind(local: SocketAddress?): CoroutineNetworkChannel {
channel.bind(local)
return this
}
}