diff --git a/src/dorkbox/network/connection/Connection.kt b/src/dorkbox/network/connection/Connection.kt index 226d0725..8cad224a 100644 --- a/src/dorkbox/network/connection/Connection.kt +++ b/src/dorkbox/network/connection/Connection.kt @@ -91,8 +91,7 @@ open class Connection(connectionParameters: ConnectionParams<*>) { private val isClosed = atomic(false) - internal var preCloseAction: suspend () -> Unit = {} - internal var postCloseAction: suspend () -> Unit = {} + internal var closeAction: suspend () -> Unit = {} // only accessed on a single thread! private var connectionLastCheckTimeNanos = 0L @@ -338,6 +337,13 @@ open class Connection(connectionParameters: ConnectionParams<*>) { * Closes the connection, and removes all connection specific listeners */ suspend fun close() { + close(true) + } + + /** + * Closes the connection, and removes all connection specific listeners + */ + internal suspend fun close(enableRemove: Boolean) { // there are 2 ways to call close. // MANUALLY // When a connection is disconnected via a timeout/expire. @@ -377,29 +383,32 @@ open class Connection(connectionParameters: ConnectionParams<*>) { logger.error("Connection $id: Unable to delete aeron publication log on close: $logFile") } - endPoint.removeConnection(this) - - - // This is set by the client so if there is a "connect()" call in the the disconnect callback, we can have proper - // lock-stop ordering for how disconnect and connect work with each-other - preCloseAction() - - val connectionSpecificListenerManager = listenerManager.value - if (connectionSpecificListenerManager != null) { - // this always has to be on event dispatch, otherwise we can have weird logic loops if we reconnect within a disconnect callback - endPoint.actionDispatch.eventLoop { - // a connection might have also registered for disconnect events (THIS IS NOT THE "CLIENT/SERVER" listenerManager!) - connectionSpecificListenerManager.notifyDisconnect(this@Connection) - } + if (enableRemove) { + endPoint.removeConnection(this) } + // NOTE: notifyDisconnect() is called in postCloseAction()!! + // This is set by the client/server so if there is a "connect()" call in the the disconnect callback, we can have proper // lock-stop ordering for how disconnect and connect work with each-other - postCloseAction() + closeAction() logger.debug {"[$id] connection closed"} } } + // called in postCloseAction(), so we don't expose our internal listenerManager + internal suspend fun doNotifyDisconnect() { + val connectionSpecificListenerManager = listenerManager.value + if (connectionSpecificListenerManager != null) { + // this always has to be on event dispatch, otherwise we can have weird logic loops if we reconnect within a disconnect callback + endPoint.actionDispatch.eventLoop { + // a connection might have also registered for disconnect events (THIS IS NOT THE "CLIENT/SERVER" listenerManager!) + connectionSpecificListenerManager.notifyDisconnect(this@Connection) + } + } + } + + // // // Generic object methods diff --git a/src/dorkbox/network/connection/EndPoint.kt b/src/dorkbox/network/connection/EndPoint.kt index 25af5437..60aee898 100644 --- a/src/dorkbox/network/connection/EndPoint.kt +++ b/src/dorkbox/network/connection/EndPoint.kt @@ -718,9 +718,12 @@ internal constructor(val type: Class<*>, aeronDriver.close() runBlocking { + // the server has to be able to call server.notifyDisconnect() on a list of connections. If we remove the connections + // inside of connection.close(), then the server does not have a list of connections to call the global notifyDisconnect() + val enableRemove = type == Client::class.java connections.forEach { logger.info { "Closing connection: ${it.id}" } - it.close() + it.close(enableRemove) } // Connections are closed first, because we want to make sure that no RMI messages can be received diff --git a/src/dorkbox/network/handshake/ServerHandshake.kt b/src/dorkbox/network/handshake/ServerHandshake.kt index cf27e66b..e6a99877 100644 --- a/src/dorkbox/network/handshake/ServerHandshake.kt +++ b/src/dorkbox/network/handshake/ServerHandshake.kt @@ -109,16 +109,11 @@ internal class ServerHandshake(private val logger: KLog } else { logger.trace { "[${message.connectKey}] Connection (${pendingConnection.id}) from $connectionString done with handshake." } - pendingConnection.postCloseAction = { + pendingConnection.closeAction = { // called on connection.close() - - // this always has to be on event dispatch, otherwise we can have weird logic loops if we reconnect within a disconnect callback - actionDispatch.launch { - listenerManager.notifyDisconnect(pendingConnection) - } + pendingConnection.doNotifyDisconnect() } - // this enables the connection to start polling for messages server.addConnection(pendingConnection)