2020-07-03 01:45:18 +02:00
/ *
2023-03-01 00:24:44 +01:00
* Copyright 2023 dorkbox , llc
2020-07-03 01:45:18 +02:00
*
* Licensed 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 .
* /
2023-05-24 09:15:55 +02:00
@file : OptIn ( ExperimentalCoroutinesApi :: class )
2020-07-03 01:45:18 +02:00
package dorkbox.network
2020-09-15 12:01:05 +02:00
import dorkbox.netUtil.IPv4
import dorkbox.netUtil.IPv6
2021-07-06 15:38:53 +02:00
import dorkbox.network.connection.Connection
2023-06-16 14:18:42 +02:00
import dorkbox.network.connection.CryptoManagement
2020-07-03 01:45:18 +02:00
import dorkbox.network.serialization.Serialization
2020-08-15 13:21:20 +02:00
import dorkbox.os.OS
2021-08-23 08:39:55 +02:00
import dorkbox.storage.Storage
2022-07-27 00:20:34 +02:00
import dorkbox.util.NamedThreadFactory
2020-07-03 01:45:18 +02:00
import io.aeron.driver.Configuration
import io.aeron.driver.ThreadingMode
2022-08-04 03:39:14 +02:00
import io.aeron.driver.exceptions.InvalidChannelException
2021-07-26 20:40:43 +02:00
import io.aeron.exceptions.DriverTimeoutException
2023-05-24 09:15:55 +02:00
import kotlinx.coroutines.ExperimentalCoroutinesApi
2021-07-26 20:40:43 +02:00
import org.agrona.concurrent.AgentTerminationException
2023-09-04 14:23:06 +02:00
import org.agrona.concurrent.BackoffIdleStrategy
2023-07-24 01:42:27 +02:00
import org.agrona.concurrent.IdleStrategy
2023-09-13 16:57:32 +02:00
import org.slf4j.Logger
2023-03-01 12:49:45 +01:00
import org.slf4j.helpers.NOPLogger
2020-07-03 01:45:18 +02:00
import java.io.File
2021-07-26 20:40:43 +02:00
import java.net.BindException
2022-08-03 00:08:13 +02:00
import java.nio.channels.ClosedByInterruptException
2022-03-03 01:23:07 +01:00
import java.util.concurrent.*
2020-07-03 01:45:18 +02:00
class ServerConfiguration : dorkbox . network . Configuration ( ) {
/ * *
* The address for the server to listen on . " * " will accept connections from all interfaces , otherwise specify
* the hostname ( or IP ) to bind to .
* /
var listenIpAddress = " * "
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
2020-09-09 01:33:09 +02:00
* The maximum number of clients allowed for a server . IPC is unlimited
2020-07-03 01:45:18 +02:00
* /
var maxClientCount = 0
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
2020-09-09 01:33:09 +02:00
* The maximum number of client connection allowed per IP address . IPC is unlimited
2020-07-03 01:45:18 +02:00
* /
var maxConnectionsPerIpAddress = 0
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-09-09 01:33:09 +02:00
2023-09-21 12:53:47 +02:00
/ * *
2023-10-28 20:54:09 +02:00
* If a connection is in a temporal state ( in the middle of a reconnect ) and a buffered connection is in use -- then how long should we consider
* a new connection from the same client as part of the same " session " .
2023-09-21 12:53:47 +02:00
*
2023-10-18 19:49:33 +02:00
* The session timeout cannot be shorter than 60 seconds , and the server will send this configuration to the client
2023-09-21 12:53:47 +02:00
* /
2023-10-28 20:54:09 +02:00
var bufferedConnectionTimeoutSeconds = TimeUnit . MINUTES . toSeconds ( 2 )
2023-09-21 12:53:47 +02:00
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2020-09-25 19:54:27 +02:00
/ * *
* Allows the user to change how endpoint settings and public key information are saved .
* /
2021-08-23 08:39:55 +02:00
override var settingsStore : Storage . Builder = Storage . Property ( ) . file ( " settings-server.db " )
2020-09-25 19:54:27 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-25 19:54:27 +02:00
field = value
}
2020-09-15 12:01:05 +02:00
/ * *
* Validates the current configuration
* /
@Suppress ( " DuplicatedCode " )
override fun validate ( ) {
2022-07-29 04:52:11 +02:00
super . validate ( )
2020-09-15 12:01:05 +02:00
// have to do some basic validation of our configuration
2021-04-27 14:19:56 +02:00
if ( listenIpAddress != listenIpAddress . lowercase ( ) ) {
2020-09-15 12:01:05 +02:00
// only do this once!
2021-04-27 14:19:56 +02:00
listenIpAddress = listenIpAddress . lowercase ( )
2020-09-15 12:01:05 +02:00
}
2021-04-30 21:18:57 +02:00
if ( maxConnectionsPerIpAddress == 0 ) { maxConnectionsPerIpAddress = maxClientCount }
2020-09-15 12:01:05 +02:00
2021-04-30 21:18:57 +02:00
require ( listenIpAddress . isNotBlank ( ) ) { " Blank listen IP address, cannot continue. " }
2022-07-29 04:52:11 +02:00
}
2023-02-23 12:32:15 +01:00
2023-09-13 16:57:32 +02:00
override fun initialize ( logger : Logger ) : dorkbox . network . ServerConfiguration {
2023-06-25 17:25:05 +02:00
return super . initialize ( logger ) as dorkbox . network . ServerConfiguration
}
override fun copy ( ) : dorkbox . network . ServerConfiguration {
val config = ServerConfiguration ( )
config . listenIpAddress = listenIpAddress
config . maxClientCount = maxClientCount
config . maxConnectionsPerIpAddress = maxConnectionsPerIpAddress
2023-10-28 20:54:09 +02:00
config . bufferedConnectionTimeoutSeconds = bufferedConnectionTimeoutSeconds
2023-06-25 17:25:05 +02:00
config . settingsStore = settingsStore
super . copy ( config )
return config
}
2023-02-23 12:32:15 +01:00
override fun equals ( other : Any ? ) : Boolean {
if ( this === other ) return true
if ( other !is ServerConfiguration ) return false
if ( ! super . equals ( other ) ) return false
if ( listenIpAddress != other . listenIpAddress ) return false
if ( maxClientCount != other . maxClientCount ) return false
if ( maxConnectionsPerIpAddress != other . maxConnectionsPerIpAddress ) return false
2023-10-28 20:54:09 +02:00
if ( bufferedConnectionTimeoutSeconds != other . bufferedConnectionTimeoutSeconds ) return false
2023-02-23 12:32:15 +01:00
if ( settingsStore != other . settingsStore ) return false
return true
}
override fun hashCode ( ) : Int {
var result = super . hashCode ( )
result = 31 * result + listenIpAddress . hashCode ( )
result = 31 * result + maxClientCount
result = 31 * result + maxConnectionsPerIpAddress
2023-10-28 20:54:09 +02:00
result = 31 * result + bufferedConnectionTimeoutSeconds . hashCode ( )
2023-02-23 12:32:15 +01:00
result = 31 * result + settingsStore . hashCode ( )
return result
}
2022-07-29 04:52:11 +02:00
}
2020-09-15 12:01:05 +02:00
2022-07-29 04:52:11 +02:00
class ClientConfiguration : dorkbox . network . Configuration ( ) {
2023-05-24 09:15:55 +02:00
2023-06-29 01:31:31 +02:00
/ * *
* Specify the UDP port to use . This port is used by the client to listen for return traffic from the server .
*
* This will normally be autoconfigured randomly to the first available port , however it can be hardcoded in the event that
* there is a reason autoconfiguration is not wanted - for example , specific firewall rules .
*
* Must be the value of an unsigned short and greater than 0
* /
var port : Int = - 1
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2022-07-29 04:52:11 +02:00
/ * *
2023-03-01 00:24:44 +01:00
* Validates the current configuration . Throws an exception if there are problems .
2022-07-29 04:52:11 +02:00
* /
@Suppress ( " DuplicatedCode " )
override fun validate ( ) {
super . validate ( )
2023-03-01 00:24:44 +01:00
2022-07-29 04:52:11 +02:00
// have to do some basic validation of our configuration
2023-06-29 01:31:31 +02:00
if ( port != - 1 ) {
// this means it was configured!
require ( port > 0 ) { " Client listen port must be > 0 " }
require ( port < 65535 ) { " Client listen port must be < 65535 " }
}
2020-09-15 12:01:05 +02:00
}
2023-02-23 12:32:15 +01:00
2023-09-13 16:57:32 +02:00
override fun initialize ( logger : Logger ) : dorkbox . network . ClientConfiguration {
2023-06-25 17:25:05 +02:00
return super . initialize ( logger ) as dorkbox . network . ClientConfiguration
}
override fun copy ( ) : dorkbox . network . ClientConfiguration {
val config = ClientConfiguration ( )
super . copy ( config )
2023-06-29 01:31:31 +02:00
config . port = port
2023-06-25 17:25:05 +02:00
return config
}
2023-02-23 12:32:15 +01:00
override fun equals ( other : Any ? ) : Boolean {
if ( this === other ) return true
if ( other !is ClientConfiguration ) return false
if ( ! super . equals ( other ) ) return false
2023-06-29 01:31:31 +02:00
if ( port != other . port ) return false
2023-02-23 12:32:15 +01:00
return true
}
2023-03-01 00:24:44 +01:00
override fun hashCode ( ) : Int {
2023-06-29 01:31:31 +02:00
var result = super . hashCode ( )
result = 31 * result + port . hashCode ( )
return result
2023-03-01 00:24:44 +01:00
}
2020-07-03 01:45:18 +02:00
}
2023-06-29 01:31:31 +02:00
abstract class Configuration protected constructor ( ) {
2023-05-24 09:15:55 +02:00
@OptIn ( ExperimentalCoroutinesApi :: class )
2020-09-15 12:01:05 +02:00
companion object {
2023-09-04 00:47:46 +02:00
/ * *
* Gets the version number .
* /
2023-10-05 13:19:10 +02:00
const val version = " 6.14 "
2023-09-04 00:47:46 +02:00
2023-09-13 16:57:32 +02:00
internal val NOP _LOGGER = NOPLogger . NOP _LOGGER
2023-04-20 17:51:07 +02:00
2020-09-15 12:01:05 +02:00
internal const val errorMessage = " Cannot set a property after the configuration context has been created! "
2022-03-08 23:33:50 +01:00
2023-06-29 01:31:31 +02:00
private val appIdRegexString = Regex ( " a-zA-Z0-9_.- " )
private val appIdRegex = Regex ( " ^[ $appIdRegexString ]+ $ " )
2023-03-01 00:24:44 +01:00
internal val networkThreadGroup = ThreadGroup ( " Network " )
2023-06-16 14:18:42 +02:00
internal val aeronThreadFactory = NamedThreadFactory ( " Aeron " , networkThreadGroup , true )
2023-03-01 00:24:44 +01:00
2023-07-01 11:41:47 +02:00
const val UDP _HANDSHAKE _STREAM _ID : Int = 0x1337cafe // 322423550
const val IPC _HANDSHAKE _STREAM _ID : Int = 0x1337c0de // 322420958
2023-03-01 00:24:44 +01:00
private val defaultAeronFilter : ( error : Throwable ) -> Boolean = { error ->
// we suppress these because they are already handled
when {
error is InvalidChannelException || error . cause is InvalidChannelException -> { false }
error is ClosedByInterruptException || error . cause is ClosedByInterruptException -> { false }
error is DriverTimeoutException || error . cause is DriverTimeoutException -> { false }
error is AgentTerminationException || error . cause is AgentTerminationException -> { false }
error is BindException || error . cause is BindException -> { false }
else -> { true }
}
2022-08-02 12:11:36 +02:00
}
2023-05-28 17:03:05 +02:00
2023-06-29 01:31:31 +02:00
/ * *
* Determines if the app ID is valid .
* /
fun isAppIdValid ( input : String ) : Boolean {
return appIdRegex . matches ( input )
}
2023-05-28 17:03:05 +02:00
/ * *
* Depending on the OS , different base locations for the Aeron log directory are preferred .
* /
2023-09-13 16:57:32 +02:00
fun defaultAeronLogLocation ( logger : Logger = NOP _LOGGER ) : File {
2023-05-28 17:03:05 +02:00
return when {
OS . isMacOsX -> {
// does the recommended location exist??
// Default is to try the RAM drive
val suggestedLocation = File ( " /Volumes/DevShm " )
if ( suggestedLocation . exists ( ) ) {
suggestedLocation
}
2023-07-23 23:36:36 +02:00
else if ( logger !== NOP _LOGGER ) {
// don't ALWAYS create it!
2023-10-05 13:18:28 +02:00
/ *
* Note : Since Mac OS does not have a built - in support for / dev / shm , we automatically create a RAM disk for the Aeron directory ( aeron . dir ) .
*
* You can create a RAM disk with the following command :
*
* $ diskutil erasevolume APFS " DISK_NAME " ` hdiutil attach - nomount ram : //$((SIZE_IN_MB * 2048))`
*
* where :
*
* DISK _NAME should be replaced with a name of your choice .
* SIZE _IN _MB is the size in megabytes for the disk ( e . g . 4096 for a 4 GB disk ) .
*
* For example , the following command creates a RAM disk named DevShm which is 8 GB in size :
*
* $ diskutil erasevolume APFS " DevShm " ` hdiutil attach - nomount ram : //$((8 * 1024 * 2048))`
*
* After this command is executed the new disk will be mounted under / Volumes / DevShm .
* /
val sizeInGB = 4
2023-07-23 23:36:36 +02:00
// on macos, we cannot rely on users to actually create this -- so we automatically do it for them.
logger . info ( " Creating a $sizeInGB GB RAM drive for best performance. " )
// hdiutil attach -nobrowse -nomount ram://4194304
val newDevice = dorkbox . executor . Executor ( )
. command ( " hdiutil " , " attach " , " -nomount " , " ram:// ${sizeInGB * 1024 * 2048} " )
. destroyOnExit ( )
. enableRead ( )
. startBlocking ( 60 , TimeUnit . SECONDS )
. output
2023-09-13 16:57:32 +02:00
. string ( ) . trim ( ) . also { if ( logger . isTraceEnabled ) { logger . trace ( " Created new disk: $it " ) } }
2023-07-23 23:36:36 +02:00
// diskutil apfs createContainer /dev/disk4
val lines = dorkbox . executor . Executor ( )
. command ( " diskutil " , " apfs " , " createContainer " , newDevice )
. destroyOnExit ( )
. enableRead ( )
. startBlocking ( 60 , TimeUnit . SECONDS )
. output
2023-09-13 16:57:32 +02:00
. lines ( ) . onEach { line -> logger . trace ( line ) }
2023-07-23 23:36:36 +02:00
val newDiskLine = lines [ lines . lastIndex - 1 ]
val disk = newDiskLine . substring ( newDiskLine . lastIndexOf ( ':' ) + 1 ) . trim ( )
// diskutil apfs addVolume disk5 APFS DevShm -nomount
dorkbox . executor . Executor ( )
. command ( " diskutil " , " apfs " , " addVolume " , disk , " APFS " , " DevShm " , " -nomount " )
. destroyOnExit ( )
. enableRead ( )
. startBlocking ( 60 , TimeUnit . SECONDS )
. output
2023-09-13 16:57:32 +02:00
. string ( ) . also { if ( logger . isTraceEnabled ) { logger . trace ( it ) } }
2023-07-23 23:36:36 +02:00
// diskutil mount nobrowse "DevShm"
dorkbox . executor . Executor ( )
. command ( " diskutil " , " mount " , " nobrowse " , " DevShm " )
. destroyOnExit ( )
. enableRead ( )
. startBlocking ( 60 , TimeUnit . SECONDS )
. output
2023-09-13 16:57:32 +02:00
. string ( ) . also { if ( logger . isTraceEnabled ) { logger . trace ( it ) } }
2023-07-23 23:36:36 +02:00
// touch /Volumes/RAMDisk/.metadata_never_index
File ( " ${suggestedLocation} /.metadata_never_index " ) . createNewFile ( )
2023-05-28 17:03:05 +02:00
2023-07-23 23:36:36 +02:00
suggestedLocation
}
else {
// we don't always want to create a ram drive!
2023-05-28 17:03:05 +02:00
OS . TEMP _DIR
}
}
OS . isLinux -> {
// this is significantly faster for linux than using the temp dir
File ( " /dev/shm/ " )
}
else -> {
OS . TEMP _DIR
}
}
}
2023-03-01 00:24:44 +01:00
}
2022-08-02 12:11:36 +02:00
2023-07-24 01:42:27 +02:00
2023-06-29 01:31:31 +02:00
/ * *
* Specify the application ID . This is necessary , as it prevents multiple instances of aeron from responding to applications that
* is not theirs . Because of the shared nature of aeron drivers , this is necessary .
*
* This is a human - readable string , and it MUST be configured the same for both the clint / server
* /
2023-07-11 15:51:28 +02:00
var appId = " "
2023-06-29 01:31:31 +02:00
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
/ * *
* In * * very * * unique circumstances , you might want to force the aeron driver to be shared between processes .
*
* This is only really applicable if the C driver is running / used .
* /
var forceAllowSharedAeronDriver = false
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2020-09-11 01:14:22 +02:00
/ * *
* Enables the ability to use the IPv4 network stack .
* /
var enableIPv4 = true
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-09-11 01:14:22 +02:00
/ * *
* Enables the ability to use the IPv6 network stack .
* /
var enableIPv6 = true
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-09-11 01:14:22 +02:00
/ * *
2021-04-30 18:22:08 +02:00
* Enables the ability use IPC ( Inter Process Communication ) . If a " loopback " is specified , and this is ' true ' , then
* IPC will be used instead - if possible . IPC is about 4 x faster than UDP in loopback situations .
2020-09-11 01:14:22 +02:00
*
* Aeron must be running in the same location for the client / server in order for this to work
* /
var enableIpc = true
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-09-11 01:14:22 +02:00
2023-07-01 11:41:47 +02:00
/ * *
* The IPC ID is used to define what ID the server will receive data on for the handshake . The client IPC ID must match this value .
* /
var ipcId = IPC _HANDSHAKE _STREAM _ID
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
/ * *
* The UDP ID is used to define what ID the server will receive data on for the handshake . The client UDP ID must match this value .
* /
var udpId = UDP _HANDSHAKE _STREAM _ID
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
* When connecting to a remote client / server , should connections be allowed if the remote machine signature has changed ?
2020-08-15 13:21:20 +02:00
*
* Setting this to false is not recommended as it is a security risk
2020-07-03 01:45:18 +02:00
* /
var enableRemoteSignatureValidation : Boolean = true
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
* How long a connection must be disconnected before we cleanup the memory associated with it
* /
2020-08-25 02:43:20 +02:00
var connectionCloseTimeoutInSeconds : Int = 10
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
2020-09-23 22:32:29 +02:00
/ * *
* How long a connection must be disconnected ( via Aeron ) before we actually consider it disconnected .
*
* Aeron Publications and Subscriptions are , and can be , constantly in flux ( because of UDP ! ) .
*
* Too low and it ' s likely to get false - positives , too high and there will be some lag when detecting if a connection has been disconnected .
* /
2022-04-04 16:28:53 +02:00
var connectionExpirationTimoutNanos = TimeUnit . SECONDS . toNanos ( 2 )
2020-09-23 22:32:29 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-23 22:32:29 +02:00
field = value
}
2022-07-29 04:52:11 +02:00
/ * *
* Set the subscription semantics for if data loss is acceptable or not , for a reliable message delivery .
* /
var isReliable = true
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
2020-09-19 19:40:21 +02:00
* Allows the user to change how endpoint settings and public key information are saved .
*
2020-09-25 19:54:27 +02:00
* Note : This field is overridden for server configurations , so that the file used is different for client / server
2020-07-03 01:45:18 +02:00
* /
2021-08-23 08:39:55 +02:00
open var settingsStore : Storage . Builder = Storage . Property ( ) . file ( " settings-client.db " )
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
2021-07-09 15:16:12 +02:00
* Specify the serialization manager to use . The type must extend `Connection` , since this will be cast
2020-07-03 01:45:18 +02:00
* /
2021-07-09 15:16:12 +02:00
var serialization : Serialization < * > = Serialization < Connection > ( )
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
2023-06-29 01:31:31 +02:00
/ * *
* What is the max stream size that can exist in memory when deciding if data chunks are in memory or on temo - file on disk .
* Data is streamed when it is too large to send in a single aeron message
2023-06-29 12:11:17 +02:00
*
* Must be >= 16 and <= 256
2023-06-29 01:31:31 +02:00
* /
2023-06-29 12:11:17 +02:00
var maxStreamSizeInMemoryMB : Int = 16
2023-06-29 01:31:31 +02:00
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
* The idle strategy used when polling the Media Driver for new messages . BackOffIdleStrategy is the DEFAULT .
*
* There are a couple strategies of importance to understand .
2020-08-15 13:21:20 +02:00
* - BusySpinIdleStrategy uses a busy spin as an idle and will eat up CPU by default .
* - BackOffIdleStrategy uses a backoff strategy of spinning , yielding , and parking to be kinder to the CPU , but to be less
2020-07-03 01:45:18 +02:00
* responsive to activity when idle for a little while .
*
* The main difference in strategies is how responsive to changes should the idler be when idle for a little bit of time and
* how much CPU should be consumed when no work is being done . There is an inherent tradeoff to consider .
* /
2023-09-04 14:23:06 +02:00
var pollIdleStrategy : IdleStrategy = BackoffIdleStrategy ( )
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
* The idle strategy used when polling the Media Driver for new messages . BackOffIdleStrategy is the DEFAULT .
*
* There are a couple strategies of importance to understand .
2020-08-15 13:21:20 +02:00
* - BusySpinIdleStrategy uses a busy spin as an idle and will eat up CPU by default .
* - BackOffIdleStrategy uses a backoff strategy of spinning , yielding , and parking to be kinder to the CPU , but to be less
2020-07-03 01:45:18 +02:00
* responsive to activity when idle for a little while .
*
* The main difference in strategies is how responsive to changes should the idler be when idle for a little bit of time and
* how much CPU should be consumed when no work is being done . There is an inherent tradeoff to consider .
* /
2023-09-04 14:23:06 +02:00
var sendIdleStrategy : IdleStrategy = BackoffIdleStrategy ( )
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
2023-07-24 01:42:27 +02:00
/ * *
* The idle strategy used by the Aeron Media Driver to write to the network when in DEDICATED mode . Null will use the aeron defaults
* /
var senderIdleStrategy : IdleStrategy ? = null
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
/ * *
* The idle strategy used by the Aeron Media Driver read from the network when in DEDICATED mode . Null will use the aeron defaults
* /
var receiverIdleStrategy : IdleStrategy ? = null
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
/ * *
* The idle strategy used by the Aeron Media Driver to read / write to the network when in NETWORK _SHARED mode . Null will use the aeron defaults
* /
var sharedIdleStrategy : IdleStrategy ? = null
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
/ * *
* The idle strategy used by the Aeron Media Driver conductor when in DEDICATED mode . Null will use the aeron defaults
* /
var conductorIdleStrategy : IdleStrategy ? = null
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
2020-08-15 13:21:20 +02:00
* # # A Media Driver , whether being run embedded or not , needs 1 - 3 threads to perform its operation .
2020-07-03 01:45:18 +02:00
*
*
* There are three main Agents in the driver :
2020-08-15 13:21:20 +02:00
* - Conductor : Responsible for reacting to client requests and house keeping duties as well as detecting loss , sending NAKs ,
2020-07-03 01:45:18 +02:00
* rotating buffers , etc .
2020-08-15 13:21:20 +02:00
* - Sender : Responsible for shovelling messages from publishers to the network .
* - Receiver : Responsible for shovelling messages from the network to subscribers .
2020-07-03 01:45:18 +02:00
*
*
* This value can be one of :
2020-08-15 13:21:20 +02:00
* - INVOKER : No threads . The client is responsible for using the MediaDriver . Context . driverAgentInvoker ( ) to invoke the duty
2020-07-03 01:45:18 +02:00
* cycle directly .
2020-08-15 13:21:20 +02:00
* - SHARED : All Agents share a single thread . 1 thread in total .
* - SHARED _NETWORK : Sender and Receiver shares a thread , conductor has its own thread . 2 threads in total .
* - DEDICATED : The default and dedicates one thread per Agent . 3 threads in total .
2020-07-03 01:45:18 +02:00
*
*
* For performance , it is recommended to use DEDICATED as long as the number of busy threads is less than or equal to the number of
* spare cores on the machine . If there are not enough cores to dedicate , then it is recommended to consider sharing some with
* SHARED _NETWORK or SHARED . INVOKER can be used for low resource environments while the application using Aeron can invoke the
* media driver to carry out its duty cycle on a regular interval .
* /
2023-07-01 11:41:47 +02:00
var threadingMode = ThreadingMode . SHARED _NETWORK
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
2020-09-11 01:14:22 +02:00
* Aeron location for the Media Driver . The default location is a TEMP dir .
* /
var aeronDirectory : File ? = null
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2023-03-17 14:02:42 +01:00
field = value ?. absoluteFile ?: value
2020-09-15 12:01:05 +02:00
}
2020-09-11 01:14:22 +02:00
2023-04-20 17:51:07 +02:00
internal var uniqueAeronDirectoryID = 0
2023-05-24 09:15:55 +02:00
2020-09-11 01:14:22 +02:00
/ * *
* Should we force the Aeron location to be unique for every instance ? This is mutually exclusive with IPC .
2020-07-03 01:45:18 +02:00
* /
2022-07-27 00:20:34 +02:00
var uniqueAeronDirectory = false
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
* The Aeron MTU value impacts a lot of things .
*
*
* The default MTU is set to a value that is a good trade - off . However , it is suboptimal for some use cases involving very large
* ( > 4 KB ) messages and for maximizing throughput above everything else . Various checks during publication and subscription / connection
* setup are done to verify a decent relationship with MTU .
*
* However , it is good to understand these relationships .
*
* The MTU on the Media Driver controls the length of the MTU of data frames . This value is communicated to the Aeron clients during
* registration . So , applications do not have to concern themselves with the MTU value used by the Media Driver and use the same value .
*
*
* An MTU value over the interface MTU will cause IP to fragment the datagram . This may increase the likelihood of loss under several
* circumstances . If increasing the MTU over the interface MTU , consider various ways to increase the interface MTU first in preparation .
*
* The MTU value indicates the largest message that Aeron will send as a single data frame .
* MTU length also has implications for socket buffer sizing .
*
* Default value is 1408 for internet ; for a LAN , 9 k is possible with jumbo frames ( if the routers / interfaces support it )
* /
var networkMtuSize = Configuration . MTU _LENGTH _DEFAULT
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
2023-07-24 01:42:27 +02:00
var ipcMtuSize = Configuration . MAX _UDP _PAYLOAD _LENGTH
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2021-07-06 15:38:53 +02:00
/ * *
* Default initial window length for flow control sender to receiver purposes . This assumes a system free of pauses .
*
* Length of Initial Window :
*
* RTT ( LAN ) = 100 usec -- Throughput = 10 Gbps )
* RTT ( LAN ) = 100 usec -- Throughput = 1 Gbps
*
* Buffer = Throughput * RTT
*
* Buffer ( 10 Gps ) = ( 10 * 1000 * 1000 * 1000 / 8 ) * 0.0001 = 125000 ( Round to 128 KB )
* Buffer ( 1 Gps ) = ( 1 * 1000 * 1000 * 1000 / 8 ) * 0.0001 = 12500 ( Round to 16 KB )
* /
2023-07-20 20:41:13 +02:00
var initialWindowLength = 16 * 1024
2021-07-06 15:38:53 +02:00
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
* This option ( ultimately SO _SNDBUF for the network socket ) can impact loss rate . Loss can occur on the sender side due
* to this buffer being too small .
*
*
* This buffer must be large enough to accommodate the MTU as a minimum . In addition , some systems , most notably Windows ,
* need plenty of buffering on the send side to reach adequate throughput rates . If too large , this buffer can increase latency
* or cause loss .
*
* This should be less than 2 MB for most use - cases .
*
* A value of 0 will ' auto - configure ' this setting
* /
2023-07-23 23:36:36 +02:00
var sendBufferSize = 0
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2020-07-03 01:45:18 +02:00
/ * *
* This option ( ultimately SO _RCVBUF for the network socket ) can impact loss rates when too small for the given processing .
* If too large , this buffer can increase latency .
*
*
* Values that tend to work well with Aeron are 2 MB to 4 MB . This setting must be large enough for the MTU of the sender . If not ,
* persistent loss can result . In addition , the receiver window length should be less than or equal to this value to allow plenty
* of space for burst traffic from a sender .
*
* A value of 0 will ' auto - configure ' this setting .
* /
2023-07-23 23:36:36 +02:00
var receiveBufferSize = 0
2020-09-15 12:01:05 +02:00
set ( value ) {
2021-04-30 21:18:57 +02:00
require ( ! contextDefined ) { errorMessage }
2020-09-15 12:01:05 +02:00
field = value
}
2021-07-26 20:40:43 +02:00
2023-02-16 21:43:45 +01:00
/ * *
* The " term " buffer is the size of EACH of the 3 ( Active , Dirty , Clean ) log files that are used to send / receive messages .
* - the smallest term buffer length is 65536 bytes ;
* - the largest term buffer length is 1 , 073 , 741 , 824 bytes ;
* - the size must be a power of 2 ;
* - maximum message length is the smallest value of 16 megabytes or ( term buffer length ) / 8 ;
*
* A value of 0 will ' auto - configure ' this setting to use the default of 64 megs . Be wary , it is easy to run out of space w / lots of clients
*
* @see [ io . aeron . driver . Configuration . TERM _BUFFER _IPC _LENGTH _DEFAULT ]
* @see [ io . aeron . logbuffer . LogBufferDescriptor . TERM _MIN _LENGTH ]
* @see [ io . aeron . logbuffer . LogBufferDescriptor . TERM _MAX _LENGTH ]
* /
var ipcTermBufferLength = 8 * 1024 * 1024
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
/ * *
* The " term " buffer is the size of EACH of the 3 ( Active , Dirty , Clean ) log files that are used to send / receive messages .
* - the smallest term buffer length is 65536 bytes ;
* - the largest term buffer length is 1 , 073 , 741 , 824 bytes ;
* - the size must be a power of 2 ;
* - maximum message length is the smallest value of 16 megabytes or ( term buffer length ) / 8 ;
*
* A value of 0 will ' auto - configure ' this setting to use the default of 16 megs . Be wary , it is easy to run out of space w / lots of clients
*
* @see [ io . aeron . driver . Configuration . TERM _BUFFER _LENGTH _DEFAULT ]
* @see [ io . aeron . logbuffer . LogBufferDescriptor . TERM _MIN _LENGTH ]
* @see [ io . aeron . logbuffer . LogBufferDescriptor . TERM _MAX _LENGTH ]
* /
var publicationTermBufferLength = 2 * 1024 * 1024
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2021-07-26 20:40:43 +02:00
/ * *
* This allows the user to setup the error filter for Aeron * SPECIFIC * error messages .
*
* Aeron WILL report more errors than normal ( which is where there are suppression statements ) , because we cannot manage
* the emitted errors from Aeron when we attempt / retry connections . This filters out those errors so we can log ( or perform an action )
* when those errors are encountered
*
2022-08-04 03:39:48 +02:00
* This is for advanced usage , and REALLY should never be over - ridden .
2021-07-26 20:40:43 +02:00
*
* @return true if the error message should be logged , false to suppress the error
* /
2023-03-01 00:24:44 +01:00
var aeronErrorFilter : ( error : Throwable ) -> Boolean = defaultAeronFilter
2021-07-26 20:40:43 +02:00
set ( value ) {
require ( ! contextDefined ) { errorMessage }
field = value
}
2020-09-15 12:01:05 +02:00
/ * *
* Internal property that tells us if this configuration has already been configured and used to create and start the Media Driver
* /
2020-09-19 19:40:21 +02:00
@Volatile
2021-04-30 21:18:57 +02:00
internal var contextDefined : Boolean = false
2020-08-15 13:21:20 +02:00
2020-09-19 19:40:21 +02:00
2020-09-15 12:01:05 +02:00
/ * *
2023-03-01 00:24:44 +01:00
* Validates the current configuration . Throws an exception if there are problems .
2020-09-15 12:01:05 +02:00
* /
@Suppress ( " DuplicatedCode " )
open fun validate ( ) {
// have to do some basic validation of our configuration
2023-07-11 15:51:28 +02:00
require ( appId . isNotEmpty ( ) ) { " The application ID must be set, as it prevents an listener from responding to differently configured applications. This is a human-readable string, and it MUST be configured the same for both the clint/server! " }
2023-06-29 01:31:31 +02:00
// The applicationID is used to create the prefix for the aeron directory -- EVEN IF the directory name is specified.
2023-07-11 15:51:28 +02:00
require ( appId . length < 32 ) { " The application ID is too long, it must be < 32 characters " }
2023-06-29 01:31:31 +02:00
2023-07-11 15:51:28 +02:00
require ( isAppIdValid ( appId ) ) { " The application ID is not valid. It may only be the following characters: $appIdRegexString " }
2023-06-29 01:31:31 +02:00
2022-07-29 04:52:11 +02:00
// can't disable everything!
require ( enableIpc || enableIPv4 || enableIPv6 ) { " At least one of IPC/IPv4/IPv6 must be enabled! " }
2021-04-30 21:18:57 +02:00
2022-07-29 04:52:11 +02:00
if ( enableIpc ) {
require ( ! uniqueAeronDirectory ) { " IPC enabled and forcing a unique Aeron directory are incompatible (IPC requires shared Aeron directories)! " }
} else {
if ( enableIPv4 && ! enableIPv6 ) {
require ( IPv4 . isAvailable ) { " IPC/IPv6 are disabled and IPv4 is enabled, but there is no IPv4 interface available! " }
}
if ( ! enableIPv4 && enableIPv6 ) {
require ( IPv6 . isAvailable ) { " IPC/IPv4 are disabled and IPv6 is enabled, but there is no IPv6 interface available! " }
}
}
2021-04-30 21:18:57 +02:00
2023-06-29 12:11:17 +02:00
require ( maxStreamSizeInMemoryMB >= 16 ) { " configuration maxStreamSizeInMemoryMB must be >= 16 " }
require ( maxStreamSizeInMemoryMB <= 256 ) { " configuration maxStreamSizeInMemoryMB must be <= 256 " } // 256 is arbitrary
2021-04-30 21:18:57 +02:00
require ( networkMtuSize > 0 ) { " configuration networkMtuSize must be > 0 " }
2023-07-14 13:39:08 +02:00
require ( networkMtuSize < Configuration . MAX _UDP _PAYLOAD _LENGTH ) { " configuration networkMtuSize must be < ${Configuration.MAX_UDP_PAYLOAD_LENGTH} " }
2023-07-24 01:42:27 +02:00
require ( ipcMtuSize > 0 ) { " configuration ipcMtuSize must be > 0 " }
require ( ipcMtuSize <= Configuration . MAX _UDP _PAYLOAD _LENGTH ) { " configuration ipcMtuSize must be <= ${Configuration.MAX_UDP_PAYLOAD_LENGTH} " }
2023-03-01 00:24:44 +01:00
2023-07-23 23:36:36 +02:00
require ( sendBufferSize >= 0 ) { " configuration socket send buffer must be >= 0 " }
require ( receiveBufferSize >= 0 ) { " configuration socket receive buffer must be >= 0 " }
2023-03-01 00:24:44 +01:00
require ( ipcTermBufferLength > 65535 ) { " configuration IPC term buffer must be > 65535 " }
require ( ipcTermBufferLength < 1 _073 _741 _824 ) { " configuration IPC term buffer must be < 1,073,741,824 " }
require ( publicationTermBufferLength > 65535 ) { " configuration publication term buffer must be > 65535 " }
require ( publicationTermBufferLength < 1 _073 _741 _824 ) { " configuration publication term buffer must be < 1,073,741,824 " }
}
2023-09-13 16:57:32 +02:00
internal open fun initialize ( logger : Logger ) : dorkbox . network . Configuration {
2023-03-01 00:24:44 +01:00
// explicitly don't set defaults if we already have the context defined!
if ( contextDefined ) {
2023-06-25 17:25:05 +02:00
return this
2023-03-01 00:24:44 +01:00
}
2023-05-24 09:15:55 +02:00
// we are starting a new context, make sure the aeron directory is unique (if specified)
if ( uniqueAeronDirectory ) {
2023-06-16 14:18:42 +02:00
uniqueAeronDirectoryID = CryptoManagement . secureRandom . let {
2023-05-24 09:15:55 +02:00
// make sure it's not 0, because 0 is special
var id = 0
while ( id == 0 ) id = it . nextInt ( )
id
}
}
2023-07-23 23:36:36 +02:00
// /*
// * Linux
// * Linux normally requires some settings of sysctl values. One is net.core.rmem_max to allow larger SO_RCVBUF and
// * net.core.wmem_max to allow larger SO_SNDBUF values to be set.
// *
// * Windows
// * Windows tends to use SO_SNDBUF values that are too small. It is recommended to use values more like 1MB or so.
// *
// * Mac/Darwin
// * Mac tends to use SO_SNDBUF values that are too small. It is recommended to use larger values, like 16KB.
// */
// if (receiveBufferSize == 0) {
// receiveBufferSize = io.aeron.driver.Configuration.SOCKET_RCVBUF_LENGTH_DEFAULT * 4
// // when {
// // OS.isLinux() ->
// // OS.isWindows() ->
// // OS.isMacOsX() ->
// // }
//
// // val rmem_max = dorkbox.network.other.NetUtil.sysctlGetInt("net.core.rmem_max")
// }
//
//
// if (sendBufferSize == 0) {
// sendBufferSize = io.aeron.driver.Configuration.SOCKET_SNDBUF_LENGTH_DEFAULT * 4
// // when {
// // OS.isLinux() ->
// // OS.isWindows() ->
// // OS.isMacOsX() ->
// // }
//
// val wmem_max = dorkbox.netUtil.SocketUtils.sysctlGetInt("net.core.wmem_max")
// }
2023-03-01 00:24:44 +01:00
2023-04-20 17:51:07 +02:00
var dir = aeronDirectory
2023-06-29 01:31:31 +02:00
2023-08-07 08:09:14 +02:00
if ( dir != null ) {
if ( forceAllowSharedAeronDriver ) {
2023-09-13 16:57:32 +02:00
logger . warn ( " Forcing the Aeron driver to be shared between processes. THIS IS DANGEROUS! " )
2023-08-07 08:09:14 +02:00
} else if ( ! dir . absolutePath . endsWith ( appId ) ) {
// we have defined an aeron directory
dir = File ( dir . absolutePath + " _ $appId " )
}
}
else {
2023-05-28 17:03:05 +02:00
val baseFileLocation = defaultAeronLogLocation ( logger )
2023-08-07 08:09:14 +02:00
val prefix = if ( appId . startsWith ( " aeron_ " ) ) {
" "
} else {
" aeron_ "
}
2023-04-20 17:51:07 +02:00
val aeronLogDirectory = if ( uniqueAeronDirectory ) {
// this is incompatible with IPC, and will not be set if IPC is enabled (error will be thrown on validate)
2023-08-07 08:09:14 +02:00
File ( baseFileLocation , " $prefix ${appId} _ ${mediaDriverIdNoDir()} " )
2023-04-20 17:51:07 +02:00
} else {
2023-08-07 08:09:14 +02:00
File ( baseFileLocation , " $prefix $appId " )
2023-04-20 17:51:07 +02:00
}
2023-06-29 01:31:31 +02:00
dir = aeronLogDirectory . absoluteFile
2023-03-01 00:24:44 +01:00
}
2023-06-29 01:31:31 +02:00
aeronDirectory = dir !! . absoluteFile
2023-04-20 17:51:07 +02:00
// cannot make any more changes to the configuration!
contextDefined = true
2023-06-25 17:25:05 +02:00
return this
2023-03-01 00:24:44 +01:00
}
// internal class for making sure that the AeronDriver is not duplicated for the same configuration (as that is entirely unnecessary)
2023-05-24 09:15:55 +02:00
internal class MediaDriverConfig ( val config : dorkbox . network . Configuration ) {
val connectionCloseTimeoutInSeconds get ( ) = config . connectionCloseTimeoutInSeconds
val threadingMode get ( ) = config . threadingMode
val networkMtuSize get ( ) = config . networkMtuSize
2023-07-24 01:42:27 +02:00
val ipcMtuSize get ( ) = config . ipcMtuSize
2023-05-24 09:15:55 +02:00
val initialWindowLength get ( ) = config . initialWindowLength
val sendBufferSize get ( ) = config . sendBufferSize
val receiveBufferSize get ( ) = config . receiveBufferSize
val aeronDirectory get ( ) = config . aeronDirectory
val uniqueAeronDirectory get ( ) = config . uniqueAeronDirectory
val uniqueAeronDirectoryID get ( ) = config . uniqueAeronDirectoryID
2023-06-29 01:31:31 +02:00
val forceAllowSharedAeronDriver get ( ) = config . forceAllowSharedAeronDriver
2023-05-24 09:15:55 +02:00
val ipcTermBufferLength get ( ) = config . ipcTermBufferLength
val publicationTermBufferLength get ( ) = config . publicationTermBufferLength
2023-07-24 01:42:27 +02:00
val conductorIdleStrategy get ( ) = config . conductorIdleStrategy
val sharedIdleStrategy get ( ) = config . sharedIdleStrategy
val receiverIdleStrategy get ( ) = config . receiverIdleStrategy
val senderIdleStrategy get ( ) = config . senderIdleStrategy
2023-05-24 09:15:55 +02:00
val aeronErrorFilter get ( ) = config . aeronErrorFilter
var contextDefined
get ( ) = config . contextDefined
set ( value ) {
config . contextDefined = value
}
2023-03-01 00:24:44 +01:00
/ * *
* Validates the current configuration . Throws an exception if there are problems .
* /
@Suppress ( " DuplicatedCode " )
2023-05-24 09:15:55 +02:00
fun validate ( ) {
2023-07-24 01:42:27 +02:00
// already validated! do nothing.
2023-04-20 17:51:07 +02:00
}
2023-03-01 00:24:44 +01:00
2023-04-20 17:51:07 +02:00
/ * *
* Normally , the hashCode MAY be duplicate for entities that are similar , but not the same identity ( via . equals ) . In the case
* of the MediaDriver config , the ID is used to uniquely identify a config that has the same VALUES , but is not the same REFERENCE .
*
* This is because configs that are DIFFERENT , but have the same values MUST use the same aeron driver .
* /
2023-08-10 06:13:55 +02:00
fun mediaDriverId ( ) : Int {
2023-05-24 09:15:55 +02:00
return config . mediaDriverId ( )
2023-03-01 00:24:44 +01:00
}
override fun equals ( other : Any ? ) : Boolean {
if ( this === other ) return true
if ( other !is MediaDriverConfig ) return false
2023-05-24 09:15:55 +02:00
return mediaDriverEquals ( config )
2023-03-01 00:24:44 +01:00
}
override fun hashCode ( ) : Int {
2023-05-24 09:15:55 +02:00
return config . mediaDriverId ( )
2023-03-01 00:24:44 +01:00
}
2023-05-24 09:15:55 +02:00
@Suppress ( " DuplicatedCode " , " RedundantIf " )
private fun mediaDriverEquals ( other : dorkbox . network . Configuration ) : Boolean {
2023-06-29 01:31:31 +02:00
if ( forceAllowSharedAeronDriver != other . forceAllowSharedAeronDriver ) return false
2023-05-24 09:15:55 +02:00
if ( connectionCloseTimeoutInSeconds != other . connectionCloseTimeoutInSeconds ) return false
if ( threadingMode != other . threadingMode ) return false
if ( networkMtuSize != other . networkMtuSize ) return false
2023-07-24 01:42:27 +02:00
if ( ipcMtuSize != other . ipcMtuSize ) return false
2023-05-24 09:15:55 +02:00
if ( initialWindowLength != other . initialWindowLength ) return false
if ( sendBufferSize != other . sendBufferSize ) return false
if ( receiveBufferSize != other . receiveBufferSize ) return false
2023-04-20 17:51:07 +02:00
2023-05-24 09:15:55 +02:00
if ( aeronDirectory != other . aeronDirectory ) return false
if ( uniqueAeronDirectory != other . uniqueAeronDirectory ) return false
if ( uniqueAeronDirectoryID != other . uniqueAeronDirectoryID ) return false
2023-04-20 17:51:07 +02:00
2023-05-24 09:15:55 +02:00
if ( ipcTermBufferLength != other . ipcTermBufferLength ) return false
if ( publicationTermBufferLength != other . publicationTermBufferLength ) return false
if ( aeronErrorFilter != other . aeronErrorFilter ) return false
2023-03-01 00:24:44 +01:00
2023-07-24 01:42:27 +02:00
if ( conductorIdleStrategy != other . conductorIdleStrategy ) return false
if ( sharedIdleStrategy != other . sharedIdleStrategy ) return false
if ( receiverIdleStrategy != other . receiverIdleStrategy ) return false
if ( senderIdleStrategy != other . senderIdleStrategy ) return false
2023-05-24 09:15:55 +02:00
return true
}
2023-03-01 00:24:44 +01:00
}
2023-05-24 09:15:55 +02:00
@Suppress ( " DuplicatedCode " , " RedundantIf " )
private fun mediaDriverEquals ( other : dorkbox . network . Configuration ) : Boolean {
2023-06-29 01:31:31 +02:00
if ( forceAllowSharedAeronDriver != other . forceAllowSharedAeronDriver ) return false
2023-03-01 00:24:44 +01:00
if ( threadingMode != other . threadingMode ) return false
if ( networkMtuSize != other . networkMtuSize ) return false
2023-07-24 01:42:27 +02:00
if ( ipcMtuSize != other . ipcMtuSize ) return false
2023-03-01 00:24:44 +01:00
if ( initialWindowLength != other . initialWindowLength ) return false
if ( sendBufferSize != other . sendBufferSize ) return false
if ( receiveBufferSize != other . receiveBufferSize ) return false
2023-04-20 17:51:07 +02:00
2023-07-24 01:42:27 +02:00
if ( conductorIdleStrategy != other . conductorIdleStrategy ) return false
if ( sharedIdleStrategy != other . sharedIdleStrategy ) return false
if ( receiverIdleStrategy != other . receiverIdleStrategy ) return false
if ( senderIdleStrategy != other . senderIdleStrategy ) return false
2023-03-01 00:24:44 +01:00
if ( aeronDirectory != other . aeronDirectory ) return false
2023-04-20 17:51:07 +02:00
if ( uniqueAeronDirectory != other . uniqueAeronDirectory ) return false
if ( uniqueAeronDirectoryID != other . uniqueAeronDirectoryID ) return false
2023-03-01 00:24:44 +01:00
if ( ipcTermBufferLength != other . ipcTermBufferLength ) return false
if ( publicationTermBufferLength != other . publicationTermBufferLength ) return false
if ( aeronErrorFilter != other . aeronErrorFilter ) return false
return true
}
2023-06-25 17:25:05 +02:00
abstract fun copy ( ) : dorkbox . network . Configuration
protected fun copy ( config : dorkbox . network . Configuration ) {
2023-07-11 15:51:28 +02:00
config . appId = appId
2023-06-29 01:31:31 +02:00
config . forceAllowSharedAeronDriver = forceAllowSharedAeronDriver
2023-06-25 17:25:05 +02:00
config . enableIPv4 = enableIPv4
config . enableIPv6 = enableIPv6
config . enableIpc = enableIpc
2023-07-01 11:41:47 +02:00
config . ipcId = ipcId
config . udpId = udpId
2023-06-25 17:25:05 +02:00
config . enableRemoteSignatureValidation = enableRemoteSignatureValidation
config . connectionCloseTimeoutInSeconds = connectionCloseTimeoutInSeconds
config . connectionExpirationTimoutNanos = connectionExpirationTimoutNanos
config . isReliable = isReliable
config . settingsStore = settingsStore
config . serialization = serialization
2023-06-29 01:31:31 +02:00
config . maxStreamSizeInMemoryMB = maxStreamSizeInMemoryMB
2023-09-04 14:23:06 +02:00
config . pollIdleStrategy = pollIdleStrategy
config . sendIdleStrategy = sendIdleStrategy
2023-06-25 17:25:05 +02:00
config . threadingMode = threadingMode
config . aeronDirectory = aeronDirectory
config . uniqueAeronDirectoryID = uniqueAeronDirectoryID
config . uniqueAeronDirectory = uniqueAeronDirectory
config . networkMtuSize = networkMtuSize
config . initialWindowLength = initialWindowLength
config . sendBufferSize = sendBufferSize
config . receiveBufferSize = receiveBufferSize
config . ipcTermBufferLength = ipcTermBufferLength
config . publicationTermBufferLength = publicationTermBufferLength
config . aeronErrorFilter = aeronErrorFilter
// config.contextDefined = contextDefined // we want to be able to reuse this config if it's a copy of an already defined config
}
2023-04-20 17:51:07 +02:00
fun mediaDriverId ( ) : Int {
2023-06-25 17:25:05 +02:00
var result = mediaDriverIdNoDir ( )
result = 31 * result + aeronDirectory . hashCode ( )
return result
}
private fun mediaDriverIdNoDir ( ) : Int {
2023-03-01 00:24:44 +01:00
var result = threadingMode . hashCode ( )
result = 31 * result + networkMtuSize
2023-07-24 01:42:27 +02:00
result = 31 * result + ipcMtuSize
2023-03-01 00:24:44 +01:00
result = 31 * result + initialWindowLength
result = 31 * result + sendBufferSize
result = 31 * result + receiveBufferSize
2023-04-20 17:51:07 +02:00
result = 31 * result + uniqueAeronDirectoryID
2023-06-25 17:25:05 +02:00
result = 31 * result + uniqueAeronDirectory . hashCode ( )
2023-04-20 17:51:07 +02:00
2023-03-01 00:24:44 +01:00
result = 31 * result + ipcTermBufferLength
result = 31 * result + publicationTermBufferLength
return result
2020-09-15 12:01:05 +02:00
}
2023-02-23 12:32:15 +01:00
override fun equals ( other : Any ? ) : Boolean {
if ( this === other ) return true
if ( other !is dorkbox . network . Configuration ) return false
2023-06-29 01:31:31 +02:00
// some values are defined here. Not necessary to list them twice
2023-03-01 00:24:44 +01:00
if ( ! mediaDriverEquals ( other ) ) return false
2023-07-11 15:51:28 +02:00
if ( appId != other . appId ) return false
2023-02-23 12:32:15 +01:00
if ( enableIPv4 != other . enableIPv4 ) return false
if ( enableIPv6 != other . enableIPv6 ) return false
if ( enableIpc != other . enableIpc ) return false
2023-07-01 11:41:47 +02:00
if ( ipcId != other . ipcId ) return false
if ( udpId != other . udpId ) return false
2023-07-24 01:42:27 +02:00
2023-02-23 12:32:15 +01:00
if ( enableRemoteSignatureValidation != other . enableRemoteSignatureValidation ) return false
if ( connectionCloseTimeoutInSeconds != other . connectionCloseTimeoutInSeconds ) return false
if ( connectionExpirationTimoutNanos != other . connectionExpirationTimoutNanos ) return false
2023-07-24 01:42:27 +02:00
2023-02-23 12:32:15 +01:00
if ( isReliable != other . isReliable ) return false
if ( settingsStore != other . settingsStore ) return false
if ( serialization != other . serialization ) return false
2023-06-29 01:31:31 +02:00
if ( maxStreamSizeInMemoryMB != other . maxStreamSizeInMemoryMB ) return false
2023-07-24 01:42:27 +02:00
2023-02-23 12:32:15 +01:00
if ( pollIdleStrategy != other . pollIdleStrategy ) return false
if ( sendIdleStrategy != other . sendIdleStrategy ) return false
2023-03-01 00:24:44 +01:00
2023-02-23 12:32:15 +01:00
if ( uniqueAeronDirectory != other . uniqueAeronDirectory ) return false
2023-04-20 17:51:07 +02:00
if ( uniqueAeronDirectoryID != other . uniqueAeronDirectoryID ) return false
2023-02-23 12:32:15 +01:00
if ( ipcTermBufferLength != other . ipcTermBufferLength ) return false
if ( contextDefined != other . contextDefined ) return false
return true
}
override fun hashCode ( ) : Int {
2023-04-20 17:51:07 +02:00
var result = mediaDriverId ( )
2023-06-25 17:25:05 +02:00
2023-07-11 15:51:28 +02:00
result = 31 * result + appId . hashCode ( )
2023-06-29 01:31:31 +02:00
result = 31 * result + forceAllowSharedAeronDriver . hashCode ( )
2023-02-23 12:32:15 +01:00
result = 31 * result + enableIPv4 . hashCode ( )
result = 31 * result + enableIPv6 . hashCode ( )
result = 31 * result + enableIpc . hashCode ( )
result = 31 * result + enableRemoteSignatureValidation . hashCode ( )
2023-07-01 11:41:47 +02:00
result = 31 * result + ipcId
result = 31 * result + udpId
2023-02-23 12:32:15 +01:00
result = 31 * result + connectionCloseTimeoutInSeconds
result = 31 * result + connectionExpirationTimoutNanos . hashCode ( )
result = 31 * result + isReliable . hashCode ( )
result = 31 * result + settingsStore . hashCode ( )
result = 31 * result + serialization . hashCode ( )
2023-06-29 01:31:31 +02:00
result = 31 * result + maxStreamSizeInMemoryMB
2023-02-23 12:32:15 +01:00
result = 31 * result + pollIdleStrategy . hashCode ( )
result = 31 * result + sendIdleStrategy . hashCode ( )
2023-06-25 17:25:05 +02:00
// aeronErrorFilter // cannot get the predictable hash code of a lambda
2023-02-23 12:32:15 +01:00
result = 31 * result + contextDefined . hashCode ( )
return result
}
2020-07-03 01:45:18 +02:00
}