From fd1f8626977cd493cfeba1932ceed9c48d7665a4 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 28 Sep 2025 08:09:06 +0200 Subject: [PATCH 01/15] reorganize configuring publishing --- build.gradle | 44 +----------------------------- gradle/configure-publishing.gradle | 30 ++++++++++++++++++++ rlib-classpath/build.gradle | 1 + rlib-collections/build.gradle | 1 + rlib-common/build.gradle | 2 ++ rlib-compiler/build.gradle | 1 + rlib-concurrent/build.gradle | 1 + rlib-functions/build.gradle | 4 +-- rlib-fx/build.gradle | 2 ++ rlib-geometry/build.gradle | 1 + rlib-io/build.gradle | 1 + rlib-logger-api/build.gradle | 1 + rlib-logger-impl/build.gradle | 2 ++ rlib-logger-slf4j/build.gradle | 2 ++ rlib-mail/build.gradle | 2 ++ rlib-network/build.gradle | 2 ++ rlib-plugin-system/build.gradle | 1 + rlib-reference/build.gradle | 1 + rlib-reusable/build.gradle | 1 + rlib-testcontainers/build.gradle | 2 ++ test-coverage/build.gradle | 6 +--- 21 files changed, 57 insertions(+), 51 deletions(-) create mode 100644 gradle/configure-publishing.gradle diff --git a/build.gradle b/build.gradle index 64da9f2c..7a7213bc 100644 --- a/build.gradle +++ b/build.gradle @@ -2,16 +2,13 @@ rootProject.version = "10.0.alpha1" group = 'javasabr.rlib' subprojects { - repositories { mavenCentral() } apply plugin: "java-library" - apply plugin: "jacoco" - apply plugin: "jacoco-report-aggregation" apply plugin: "java-test-fixtures" - apply plugin: 'maven-publish' + apply plugin: "jacoco" java { toolchain { @@ -42,16 +39,6 @@ subprojects { testAnnotationProcessor libs.lombok } - /*compileJava { - inputs.property("moduleName", jar.baseName) - doFirst { - options.compilerArgs = [ - '--module-path', classpath.asPath, - ] - classpath = files() - } - }*/ - tasks.withType(JavaCompile).configureEach { options.encoding = "UTF-8" } @@ -76,35 +63,6 @@ subprojects { from sourceSets.main.allSource } - publishing { - repositories { - maven { - name = "GitlabPackages" - url = uri("https://gitlab.com/api/v4/projects/37512056/packages/maven") - credentials(HttpHeaderCredentials) { - name = "Private-Token" - value = project.findProperty("gitlab.token") ?: System.getenv("GITLAB_TOKEN") - } - authentication { - header(HttpHeaderAuthentication) - } - } - } - - publications { - mavenJava(MavenPublication) { - from components.java - version = rootProject.version - afterEvaluate { - artifactId = jar.archiveBaseName.get() - groupId = rootProject.group - } - artifact sourcesJar - artifact javadocJar - } - } - } - configurations { testArtifacts.extendsFrom testRuntime } diff --git a/gradle/configure-publishing.gradle b/gradle/configure-publishing.gradle new file mode 100644 index 00000000..833482b0 --- /dev/null +++ b/gradle/configure-publishing.gradle @@ -0,0 +1,30 @@ +apply plugin: "maven-publish" + +publishing { + repositories { + maven { + name = "GitlabPackages" + url = uri("https://gitlab.com/api/v4/projects/37512056/packages/maven") + credentials(HttpHeaderCredentials) { + name = "Private-Token" + value = project.findProperty("gitlab.token") ?: System.getenv("GITLAB_TOKEN") + } + authentication { + header(HttpHeaderAuthentication) + } + } + } + + publications { + mavenJava(MavenPublication) { + from components.java + version = rootProject.version + afterEvaluate { + artifactId = jar.archiveBaseName.get() + groupId = rootProject.group + } + artifact sourcesJar + artifact javadocJar + } + } +} diff --git a/rlib-classpath/build.gradle b/rlib-classpath/build.gradle index 70a1fabd..31ec1664 100644 --- a/rlib-classpath/build.gradle +++ b/rlib-classpath/build.gradle @@ -1,3 +1,4 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" dependencies { api projects.rlibCommon diff --git a/rlib-collections/build.gradle b/rlib-collections/build.gradle index 8acc7aeb..64359f8e 100644 --- a/rlib-collections/build.gradle +++ b/rlib-collections/build.gradle @@ -1,3 +1,4 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" dependencies { api projects.rlibCommon diff --git a/rlib-common/build.gradle b/rlib-common/build.gradle index b3fd7a24..996db654 100644 --- a/rlib-common/build.gradle +++ b/rlib-common/build.gradle @@ -1,3 +1,5 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" + dependencies { api projects.rlibLoggerApi } diff --git a/rlib-compiler/build.gradle b/rlib-compiler/build.gradle index 70a1fabd..31ec1664 100644 --- a/rlib-compiler/build.gradle +++ b/rlib-compiler/build.gradle @@ -1,3 +1,4 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" dependencies { api projects.rlibCommon diff --git a/rlib-concurrent/build.gradle b/rlib-concurrent/build.gradle index db4c8ef6..d065f972 100644 --- a/rlib-concurrent/build.gradle +++ b/rlib-concurrent/build.gradle @@ -1,3 +1,4 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" dependencies { api projects.rlibCollections diff --git a/rlib-functions/build.gradle b/rlib-functions/build.gradle index 37ec34f9..450a0ed2 100644 --- a/rlib-functions/build.gradle +++ b/rlib-functions/build.gradle @@ -1,3 +1 @@ - -dependencies { -} \ No newline at end of file +apply from: "$rootDir/gradle/configure-publishing.gradle" diff --git a/rlib-fx/build.gradle b/rlib-fx/build.gradle index f1ed3631..10ac9960 100644 --- a/rlib-fx/build.gradle +++ b/rlib-fx/build.gradle @@ -2,6 +2,8 @@ plugins { id 'org.openjfx.javafxplugin' version '0.1.0' } +apply from: "$rootDir/gradle/configure-publishing.gradle" + dependencies { api projects.rlibCommon api projects.rlibReference diff --git a/rlib-geometry/build.gradle b/rlib-geometry/build.gradle index f6679eef..7515479c 100644 --- a/rlib-geometry/build.gradle +++ b/rlib-geometry/build.gradle @@ -1,3 +1,4 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" dependencies { api projects.rlibCommon diff --git a/rlib-io/build.gradle b/rlib-io/build.gradle index dec474f6..2f86818a 100644 --- a/rlib-io/build.gradle +++ b/rlib-io/build.gradle @@ -1,3 +1,4 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" dependencies { api projects.rlibCommon diff --git a/rlib-logger-api/build.gradle b/rlib-logger-api/build.gradle index e69de29b..4838f74a 100644 --- a/rlib-logger-api/build.gradle +++ b/rlib-logger-api/build.gradle @@ -0,0 +1 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" \ No newline at end of file diff --git a/rlib-logger-impl/build.gradle b/rlib-logger-impl/build.gradle index dd159500..60dc1360 100644 --- a/rlib-logger-impl/build.gradle +++ b/rlib-logger-impl/build.gradle @@ -1,3 +1,5 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" + dependencies { api projects.rlibCommon api projects.rlibCollections diff --git a/rlib-logger-slf4j/build.gradle b/rlib-logger-slf4j/build.gradle index 1fc24540..c8eee225 100644 --- a/rlib-logger-slf4j/build.gradle +++ b/rlib-logger-slf4j/build.gradle @@ -1,3 +1,5 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" + dependencies { api projects.rlibLoggerApi api libs.slf4j.api diff --git a/rlib-mail/build.gradle b/rlib-mail/build.gradle index 3f6a80e5..66d714f1 100644 --- a/rlib-mail/build.gradle +++ b/rlib-mail/build.gradle @@ -1,3 +1,5 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" + dependencies { api projects.rlibCommon api libs.bundles.mail diff --git a/rlib-network/build.gradle b/rlib-network/build.gradle index ef0d1c95..0a04377b 100644 --- a/rlib-network/build.gradle +++ b/rlib-network/build.gradle @@ -1,3 +1,5 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" + dependencies { api projects.rlibCommon api projects.rlibClasspath diff --git a/rlib-plugin-system/build.gradle b/rlib-plugin-system/build.gradle index 126f9f5d..cdc11bce 100644 --- a/rlib-plugin-system/build.gradle +++ b/rlib-plugin-system/build.gradle @@ -1,3 +1,4 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" dependencies { api projects.rlibCommon diff --git a/rlib-reference/build.gradle b/rlib-reference/build.gradle index 7a1f495a..3ba0c727 100644 --- a/rlib-reference/build.gradle +++ b/rlib-reference/build.gradle @@ -1,3 +1,4 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" dependencies { compileOnly projects.rlibReusable diff --git a/rlib-reusable/build.gradle b/rlib-reusable/build.gradle index db4c8ef6..d065f972 100644 --- a/rlib-reusable/build.gradle +++ b/rlib-reusable/build.gradle @@ -1,3 +1,4 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" dependencies { api projects.rlibCollections diff --git a/rlib-testcontainers/build.gradle b/rlib-testcontainers/build.gradle index c143c6a5..16131cd8 100644 --- a/rlib-testcontainers/build.gradle +++ b/rlib-testcontainers/build.gradle @@ -1,3 +1,5 @@ +apply from: "$rootDir/gradle/configure-publishing.gradle" + dependencies { api projects.rlibCommon api libs.testcontainers diff --git a/test-coverage/build.gradle b/test-coverage/build.gradle index 7b385d79..af53c2c4 100644 --- a/test-coverage/build.gradle +++ b/test-coverage/build.gradle @@ -1,6 +1,4 @@ -plugins { - id 'jacoco-report-aggregation' -} +apply plugin: "jacoco-report-aggregation" dependencies { jacocoAggregation projects.rlibClasspath @@ -20,5 +18,3 @@ dependencies { jacocoAggregation projects.rlibReusable jacocoAggregation projects.rlibTestcontainers } - -publishing.publications.remove(publishing.publications.mavenJava) \ No newline at end of file From d3c6c1944662b5885b701528a4ab4868d46d2fdf Mon Sep 17 00:00:00 2001 From: javasabr Date: Wed, 1 Oct 2025 05:50:44 +0200 Subject: [PATCH 02/15] redesign network api --- lombok.config | 1 + .../javasabr/rlib/common/util/AsyncUtils.java | 12 +- .../java/javasabr/rlib/common/util/Utils.java | 5 +- .../java/javasabr/rlib/logger/api/Logger.java | 146 ++++-- .../rlib/network/BufferAllocator.java | 30 +- .../javasabr/rlib/network/Connection.java | 36 +- .../javasabr/rlib/network/NetworkConfig.java | 24 +- .../javasabr/rlib/network/NetworkCryptor.java | 12 +- .../javasabr/rlib/network/NetworkFactory.java | 113 ++--- .../rlib/network/ServerNetworkConfig.java | 26 +- .../rlib/network/UnsafeConnection.java | 8 +- ...ion.java => NetworkPacketDescription.java} | 3 +- .../rlib/network/client/ClientNetwork.java | 25 +- .../client/impl/DefaultClientNetwork.java | 119 +++-- .../rlib/network/impl/AbstractConnection.java | 28 +- .../rlib/network/impl/AbstractNetwork.java | 23 +- .../network/impl/AbstractSSLConnection.java | 8 +- .../rlib/network/impl/DefaultConnection.java | 12 +- .../network/impl/DefaultDataConnection.java | 26 +- .../impl/DefaultDataSSLConnection.java | 26 +- .../network/impl/IdBasedPacketConnection.java | 28 +- .../network/impl/StringDataConnection.java | 6 +- .../network/impl/StringDataSSLConnection.java | 6 +- .../network/packet/IdBasedNetworkPacket.java | 20 + .../rlib/network/packet/IdBasedPacket.java | 20 - .../packet/IdBasedReadableNetworkPacket.java | 18 + .../network/packet/IdBasedReadablePacket.java | 28 - .../packet/IdBasedWritableNetworkPacket.java | 7 + .../network/packet/IdBasedWritablePacket.java | 8 - .../network/packet/MarkerNetworkPacket.java | 6 + .../{Packet.java => NetworkPacket.java} | 6 +- ...etReader.java => NetworkPacketReader.java} | 2 +- ...etWriter.java => NetworkPacketWriter.java} | 2 +- ...Packet.java => ReadableNetworkPacket.java} | 8 +- .../packet/ReusableWritablePacket.java | 2 +- .../network/packet/WritableNetworkPacket.java | 25 + .../rlib/network/packet/WritablePacket.java | 135 ----- .../AbstractIdBasedReadableNetworkPacket.java | 10 + .../impl/AbstractIdBasedReadablePacket.java | 29 -- .../packet/impl/AbstractNetworkPacket.java | 48 ++ .../impl/AbstractNetworkPacketReader.java | 417 +++++++++++++++ ....java => AbstractNetworkPacketWriter.java} | 223 ++++---- .../network/packet/impl/AbstractPacket.java | 46 -- .../packet/impl/AbstractPacketReader.java | 478 ------------------ .../impl/AbstractReadableNetworkPacket.java | 126 +++++ .../packet/impl/AbstractReadablePacket.java | 161 ------ ...bstractReusableWritableNetworkPacket.java} | 44 +- ...va => AbstractSslNetworkPacketReader.java} | 100 ++-- ...va => AbstractSslNetworkPacketWriter.java} | 135 +++-- .../impl/AbstractWritableNetworkPacket.java | 106 ++++ .../packet/impl/AbstractWritablePacket.java | 30 -- ...r.java => DefaultNetworkPacketReader.java} | 36 +- ...r.java => DefaultNetworkPacketWriter.java} | 27 +- .../impl/DefaultReadableNetworkPacket.java | 13 + .../packet/impl/DefaultReadablePacket.java | 10 - ...ava => DefaultSslNetworkPacketReader.java} | 20 +- ...ava => DefaultSslNetworkPacketWriter.java} | 20 +- .../impl/DefaultWritableNetworkPacket.java | 9 + .../packet/impl/DefaultWritablePacket.java | 8 - ...r.java => IdBasedNetworkPacketWriter.java} | 22 +- .../packet/impl/IdBasedPacketReader.java | 20 +- .../packet/impl/SSLWritablePacket.java | 20 - .../packet/impl/SslWritableNetworkPacket.java | 20 + .../packet/impl/StringReadablePacket.java | 2 +- ....java => StringWritableNetworkPacket.java} | 4 +- .../packet/impl/WritablePacketWrapper.java | 11 +- .../ReadableNetworkPacketRegistry.java | 106 ++++ .../registry/ReadablePacketRegistry.java | 130 ----- .../IdBasedReadableNetworkPacketRegistry.java | 168 ++++++ .../impl/IdBasedReadablePacketRegistry.java | 201 -------- .../rlib/network/server/ServerNetwork.java | 10 - .../server/impl/DefaultServerNetwork.java | 117 +++-- .../rlib/network/util/NetworkUtils.java | 10 +- .../rlib/network/BaseNetworkTest.java | 34 +- .../rlib/network/DefaultNetworkTest.java | 159 +++--- ...asedReadableNetworkPacketRegistryTest.java | 123 +++++ .../IdBasedReadablePacketRegistryTest.java | 122 ----- .../rlib/network/StringNetworkTest.java | 172 ++++--- .../rlib/network/StringSSLNetworkTest.java | 26 +- .../javasabr/rlib/network/package-info.java | 4 + 80 files changed, 2160 insertions(+), 2427 deletions(-) create mode 100644 lombok.config rename rlib-network/src/main/java/javasabr/rlib/network/annotation/{PacketDescription.java => NetworkPacketDescription.java} (90%) create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedNetworkPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedPacket.java create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedReadableNetworkPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedReadablePacket.java create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedWritableNetworkPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedWritablePacket.java create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/MarkerNetworkPacket.java rename rlib-network/src/main/java/javasabr/rlib/network/packet/{Packet.java => NetworkPacket.java} (68%) rename rlib-network/src/main/java/javasabr/rlib/network/packet/{PacketReader.java => NetworkPacketReader.java} (84%) rename rlib-network/src/main/java/javasabr/rlib/network/packet/{PacketWriter.java => NetworkPacketWriter.java} (80%) rename rlib-network/src/main/java/javasabr/rlib/network/packet/{ReadablePacket.java => ReadableNetworkPacket.java} (55%) create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/WritableNetworkPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/WritablePacket.java create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractIdBasedReadableNetworkPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractIdBasedReadablePacket.java create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{AbstractPacketWriter.java => AbstractNetworkPacketWriter.java} (55%) delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketReader.java create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadablePacket.java rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{AbstractReusableWritablePacket.java => AbstractReusableWritableNetworkPacket.java} (76%) rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{AbstractSSLPacketReader.java => AbstractSslNetworkPacketReader.java} (73%) rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{AbstractSSLPacketWriter.java => AbstractSslNetworkPacketWriter.java} (59%) create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractWritableNetworkPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractWritablePacket.java rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{DefaultPacketReader.java => DefaultNetworkPacketReader.java} (53%) rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{DefaultPacketWriter.java => DefaultNetworkPacketWriter.java} (64%) create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadableNetworkPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadablePacket.java rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{DefaultSSLPacketReader.java => DefaultSslNetworkPacketReader.java} (73%) rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{DefaultSSLPacketWriter.java => DefaultSslNetworkPacketWriter.java} (72%) create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultWritableNetworkPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultWritablePacket.java rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{IdBasedPacketWriter.java => IdBasedNetworkPacketWriter.java} (60%) delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SSLWritablePacket.java create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWritableNetworkPacket.java rename rlib-network/src/main/java/javasabr/rlib/network/packet/impl/{StringWritablePacket.java => StringWritableNetworkPacket.java} (81%) create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadableNetworkPacketRegistry.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/registry/impl/IdBasedReadableNetworkPacketRegistry.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/registry/impl/IdBasedReadablePacketRegistry.java create mode 100644 rlib-network/src/test/java/javasabr/rlib/network/IdBasedReadableNetworkPacketRegistryTest.java delete mode 100644 rlib-network/src/test/java/javasabr/rlib/network/IdBasedReadablePacketRegistryTest.java create mode 100644 rlib-network/src/test/java/javasabr/rlib/network/package-info.java diff --git a/lombok.config b/lombok.config new file mode 100644 index 00000000..b6e33001 --- /dev/null +++ b/lombok.config @@ -0,0 +1 @@ +lombok.log.custom.declaration = javasabr.rlib.logger.api.Logger javasabr.rlib.logger.api.LoggerManager.getLogger(TYPE) \ No newline at end of file diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/AsyncUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/AsyncUtils.java index 31d4a15b..16fa0e9c 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/AsyncUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/AsyncUtils.java @@ -1,26 +1,28 @@ package javasabr.rlib.common.util; +import java.util.Objects; import java.util.concurrent.CompletionException; -import org.jspecify.annotations.NullMarked; +import lombok.experimental.UtilityClass; import org.jspecify.annotations.Nullable; /** * @author JavaSaBr */ -@NullMarked +@UtilityClass public class AsyncUtils { - public static @Nullable T skip(Throwable throwable) { + @Nullable + public static T skip(Throwable throwable) { return null; } - public static @Nullable T continueCompletableStage(@Nullable T result, @Nullable Throwable throwable) { + public static T continueCompletableStage(@Nullable T result, @Nullable Throwable throwable) { if (throwable instanceof RuntimeException) { throw (RuntimeException) throwable; } else if (throwable != null) { throw new CompletionException(throwable); } else { - return result; + return Objects.requireNonNull(result); } } } diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/Utils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/Utils.java index 09474c2e..ac62fb51 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/Utils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/Utils.java @@ -7,6 +7,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.concurrent.Callable; import javasabr.rlib.common.function.NotNullSafeBiConsumer; import javasabr.rlib.common.function.NotNullSafeBiFunction; import javasabr.rlib.common.function.NotNullSafeConsumer; @@ -145,9 +146,9 @@ public static void unchecked( } } - public static R uncheckedGet(NotNullSafeFactory function) { + public static R uncheckedGet(Callable function) { try { - return function.get(); + return function.call(); } catch (IOException e) { throw new UncheckedIOException(e); } catch (Exception e) { diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java index bdd0248d..ffd0b5fb 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java @@ -17,10 +17,10 @@ interface Factory { } @FunctionalInterface - interface N1Factory { + interface N1Factory { @NonNull - String make(F arg1); + String make(A arg1); } @FunctionalInterface @@ -31,24 +31,24 @@ interface IntFactory { } @FunctionalInterface - interface IntN1Factory { + interface IntN1Factory { @NonNull - String make(int arg1, F arg2); + String make(int arg1, B arg2); } @FunctionalInterface - interface N2Factory { + interface N2Factory { @NonNull - String make(F arg1, S arg2); + String make(A arg1, B arg2); } @FunctionalInterface - interface N1IntFactory { + interface N1IntFactory { @NonNull - String make(F arg1, int arg2); + String make(A arg1, int arg2); } @FunctionalInterface @@ -59,17 +59,24 @@ interface Int2Factory { } @FunctionalInterface - interface N3Factory { + interface N3Factory { @NonNull - String make(F arg1, S arg2, T arg3); + String make(A arg1, B arg2, C arg3); } @FunctionalInterface - interface N4Factory { + interface Int2N1Factory { @NonNull - String make(F arg1, S arg2, T arg3, FO arg4); + String make(int arg1, int arg2, C arg3); + } + + @FunctionalInterface + interface N4Factory { + + @NonNull + String make(A arg1, B arg2, C arg3, D arg4); } /** @@ -85,19 +92,19 @@ default void debug(int arg1, @NonNull IntFactory factory) { print(LoggerLevel.DEBUG, arg1, factory); } - default void debug(T arg1, @NonNull N1Factory factory) { + default void debug(A arg1, @NonNull N1Factory factory) { print(LoggerLevel.DEBUG, arg1, factory); } - default void debug(int arg1, F arg2, @NonNull IntN1Factory factory) { + default void debug(int arg1, B arg2, @NonNull IntN1Factory factory) { print(LoggerLevel.DEBUG, arg1, arg2, factory); } - default void debug(F arg1, S arg2, @NonNull N2Factory factory) { + default void debug(A arg1, B arg2, @NonNull N2Factory factory) { print(LoggerLevel.DEBUG, arg1, arg2, factory); } - default void debug(F arg1, int arg2, @NonNull N1IntFactory factory) { + default void debug(A arg1, int arg2, @NonNull N1IntFactory factory) { print(LoggerLevel.DEBUG, arg1, arg2, factory); } @@ -113,6 +120,22 @@ default void error(@NonNull String message) { print(LoggerLevel.ERROR, message); } + default void error(A arg1, @NonNull N1Factory factory) { + print(LoggerLevel.ERROR, arg1, factory); + } + + default void error(int arg1, @NonNull IntFactory factory) { + print(LoggerLevel.ERROR, arg1, factory); + } + + default void error(int arg1, B arg2, @NonNull IntN1Factory factory) { + print(LoggerLevel.ERROR, arg1, arg2, factory); + } + + default void error(int arg1, int arg2, C arg3, @NonNull Int2N1Factory factory) { + print(LoggerLevel.ERROR, arg1, arg2, arg3, factory); + } + default void error(@NonNull Throwable exception) { print(LoggerLevel.ERROR, exception); } @@ -125,11 +148,11 @@ default void info(T arg1, @NonNull N1Factory factory) { print(LoggerLevel.INFO, arg1, factory); } - default void info(F arg1, S arg2, @NonNull N2Factory factory) { + default void info(A arg1, B arg2, @NonNull N2Factory factory) { print(LoggerLevel.INFO, arg1, arg2, factory); } - default void info(F arg1, S arg2, T arg3, @NonNull N3Factory factory) { + default void info(A arg1, B arg2, C arg3, @NonNull N3Factory factory) { print(LoggerLevel.INFO, arg1, arg2, arg3, factory); } @@ -140,6 +163,20 @@ default boolean enabled(@NonNull LoggerLevel level) { return level.enabled(); } + /** + * Check of enabling the warning level. + */ + default boolean warningEnabled() { + return enabled(LoggerLevel.WARNING); + } + + /** + * Check of enabling the debug level. + */ + default boolean debugEnabled() { + return enabled(LoggerLevel.DEBUG); + } + /** * Override the enabling status of the logger level. */ @@ -162,16 +199,20 @@ default void warning(A arg1, @NonNull N1Factory factory) { print(LoggerLevel.WARNING, arg1, factory); } - default void warning(F arg1, S arg2, @NonNull N2Factory factory) { + default void warning(A arg1, B arg2, @NonNull N2Factory factory) { print(LoggerLevel.WARNING, arg1, arg2, factory); } - default void warning( - F arg1, - S arg2, - T arg3, - FO arg4, - @NonNull N4Factory factory) { + default void warning(A arg1, B arg2, C arg3, @NonNull N3Factory factory) { + print(LoggerLevel.WARNING, arg1, arg2, arg3, factory); + } + + default void warning( + A arg1, + B arg2, + C arg3, + D arg4, + @NonNull N4Factory factory) { print(LoggerLevel.WARNING, arg1, arg2, arg3, arg4, factory); } @@ -179,7 +220,7 @@ default void warning( void print(@NonNull LoggerLevel level, @NonNull Throwable exception); - default void print(@NonNull LoggerLevel level, T arg1, @NonNull N1Factory factory) { + default void print(@NonNull LoggerLevel level, A arg1, @NonNull N1Factory factory) { if (enabled(level)) { print(level, factory.make(arg1)); } @@ -191,31 +232,31 @@ default void print(@NonNull LoggerLevel level, int arg1, @NonNull IntFactory fac } } - default void print( + default void print( @NonNull LoggerLevel level, int arg1, - F arg2, - @NonNull IntN1Factory factory) { + B arg2, + @NonNull IntN1Factory factory) { if (enabled(level)) { print(level, factory.make(arg1, arg2)); } } - default void print( + default void print( @NonNull LoggerLevel level, - F arg1, - S arg2, - @NonNull N2Factory factory) { + A arg1, + B arg2, + @NonNull N2Factory factory) { if (enabled(level)) { print(level, factory.make(arg1, arg2)); } } - default void print( + default void print( @NonNull LoggerLevel level, - F arg1, + A arg1, int arg2, - @NonNull N1IntFactory factory) { + @NonNull N1IntFactory factory) { if (enabled(level)) { print(level, factory.make(arg1, arg2)); } @@ -231,24 +272,35 @@ default void print( } } - default void print( + default void print( @NonNull LoggerLevel level, - F arg1, - S arg2, - T arg3, - @NonNull N3Factory factory) { + A arg1, + B arg2, + C arg3, + @NonNull N3Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2, arg3)); + } + } + + default void print( + @NonNull LoggerLevel level, + int arg1, + int arg2, + C arg3, + @NonNull Int2N1Factory factory) { if (enabled(level)) { print(level, factory.make(arg1, arg2, arg3)); } } - default void print( + default void print( @NonNull LoggerLevel level, - F arg1, - S arg2, - T arg3, - FO arg4, - @NonNull N4Factory factory) { + A arg1, + B arg2, + C arg3, + D arg4, + @NonNull N4Factory factory) { if (enabled(level)) { print(level, factory.make(arg1, arg2, arg3, arg4)); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/BufferAllocator.java b/rlib-network/src/main/java/javasabr/rlib/network/BufferAllocator.java index 52810c1d..d713c3f1 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/BufferAllocator.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/BufferAllocator.java @@ -11,63 +11,41 @@ public interface BufferAllocator { /** * Get a new read buffer to use. - * - * @return the new buffer. */ ByteBuffer takeReadBuffer(); /** * Get a new pending buffer to use. - * - * @return the new pending buffer. */ ByteBuffer takePendingBuffer(); /** * Get a new write buffer to use. - * - * @return the new buffer. */ ByteBuffer takeWriteBuffer(); /** * Get a new buffer with requested capacity. - * - * @param bufferSize the size of new buffer. - * @return the new buffer. */ ByteBuffer takeBuffer(int bufferSize); /** - * Store an old read buffer if need. - * - * @param buffer the old read buffer. - * @return this allocator. + * Store an already used read buffer. */ BufferAllocator putReadBuffer(ByteBuffer buffer); /** - * Store an old pending buffer if need. - * - * @param buffer the old pending buffer. - * @return this allocator. + * Store an already used pending buffer. */ BufferAllocator putPendingBuffer(ByteBuffer buffer); /** - * Store an old write buffer if need. - * - * @param buffer the old write buffer. - * @return this allocator. + * Store an already used write buffer. */ BufferAllocator putWriteBuffer(ByteBuffer buffer); /** - * Store an old byte buffer if need. - * - * @param buffer the old byte buffer. - * @return this allocator. + * Store an already used byte buffer. */ - BufferAllocator putBuffer(ByteBuffer buffer); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/Connection.java b/rlib-network/src/main/java/javasabr/rlib/network/Connection.java index 62410328..6e6a0669 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/Connection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/Connection.java @@ -2,9 +2,8 @@ import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; -import javasabr.rlib.network.packet.ReadablePacket; -import javasabr.rlib.network.packet.WritablePacket; -import lombok.AllArgsConstructor; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; import reactor.core.publisher.Flux; /** @@ -12,27 +11,20 @@ * * @author JavaSaBr */ -public interface Connection { +public interface Connection { - @AllArgsConstructor - class ReceivedPacketEvent, R extends ReadablePacket> { - public final C connection; - public final R packet; - } + record ReceivedPacketEvent, R extends ReadableNetworkPacket>( + C connection, R packet) {} /** * Get a remote address of this connection. - * - * @return the remote address. */ - String getRemoteAddress(); + String remoteAddress(); /** * Get a timestamp of last write/read activity. - * - * @return the timestamp of last write/read activity. */ - long getLastActivity(); + long lastActivity(); /** * Close this connection if this connection is still opened. @@ -40,46 +32,34 @@ class ReceivedPacketEvent, R extends ReadablePacket> void close(); /** - * Check a closed state of this connection. - * * @return true if this connection is already closed. */ - boolean isClosed(); + boolean closed(); /** * Send a packet to connection's owner. - * - * @param packet the writable packet. */ void send(W packet); /** * Send a packet to connection's owner with async feedback of this sending. * - * @param packet the writable packet. * @return the async result with true if the packet was sent or false if sending was failed. - * @since 9.5.0 */ CompletableFuture sendWithFeedback(W packet); /** * Register a consumer to handle received packets. - * - * @param consumer the consumer. */ void onReceive(BiConsumer, ? super R> consumer); /** * Get a stream of received packet events. - * - * @return the stream of received packet events. */ Flux, ? extends R>> receivedEvents(); /** * Get a stream of received packets. - * - * @return the stream of received packets. */ Flux receivedPackets(); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/NetworkConfig.java b/rlib-network/src/main/java/javasabr/rlib/network/NetworkConfig.java index 7c2ce76b..7dbbd664 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/NetworkConfig.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/NetworkConfig.java @@ -3,6 +3,7 @@ import java.nio.ByteOrder; import lombok.Builder; import lombok.Getter; +import lombok.experimental.Accessors; /** * The interface to implement a network config. @@ -13,6 +14,7 @@ public interface NetworkConfig { @Builder @Getter + @Accessors(fluent = true, chain = false) class SimpleNetworkConfig implements NetworkConfig { @Builder.Default @@ -31,49 +33,43 @@ class SimpleNetworkConfig implements NetworkConfig { NetworkConfig DEFAULT_CLIENT = new NetworkConfig() { @Override - public String getThreadGroupName() { + public String threadGroupName() { return "ClientNetworkThread"; } }; /** * Get a group name of network threads. - * - * @return the group name. */ - default String getThreadGroupName() { + default String threadGroupName() { return "NetworkThread"; } /** * Get size of buffer with used to collect received data from network. - * - * @return the read buffer's size. */ - default int getReadBufferSize() { + default int readBufferSize() { return 2048; } /** * Get size of buffer with pending data. Pending buffer allows to construct a packet with bigger data than - * {@link #getReadBufferSize()}. It should be at least 2x of {@link #getReadBufferSize()} + * {@link #readBufferSize()}. It should be at least 2x of {@link #readBufferSize()} * * @return the pending buffer's size. */ - default int getPendingBufferSize() { - return getReadBufferSize() * 2; + default int pendingBufferSize() { + return readBufferSize() * 2; } /** * Get size of buffer which used to serialize packets to bytes. - * - * @return the write buffer's size. */ - default int getWriteBufferSize() { + default int writeBufferSize() { return 2048; } - default ByteOrder getByteOrder() { + default ByteOrder byteOrder() { return ByteOrder.BIG_ENDIAN; } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/NetworkCryptor.java b/rlib-network/src/main/java/javasabr/rlib/network/NetworkCryptor.java index b9fb1fe7..bbd5c2c9 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/NetworkCryptor.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/NetworkCryptor.java @@ -15,13 +15,15 @@ public interface NetworkCryptor { */ NetworkCryptor NULL = new NetworkCryptor() { + @Nullable @Override - public @Nullable ByteBuffer decrypt(ByteBuffer data, int length, ByteBuffer toStore) { + public ByteBuffer decrypt(ByteBuffer data, int length, ByteBuffer toStore) { return null; } + @Nullable @Override - public @Nullable ByteBuffer encrypt(ByteBuffer data, int length, ByteBuffer toStore) { + public ByteBuffer encrypt(ByteBuffer data, int length, ByteBuffer toStore) { return null; } }; @@ -34,7 +36,8 @@ public interface NetworkCryptor { * @param toStore the buffer to store decrypted data. * @return the buffer with decrypted data or null if don't need to decrypt anything. */ - @Nullable ByteBuffer decrypt(ByteBuffer data, int length, ByteBuffer toStore); + @Nullable + ByteBuffer decrypt(ByteBuffer data, int length, ByteBuffer toStore); /** * Encrypt data. @@ -44,5 +47,6 @@ public interface NetworkCryptor { * @param toStore the buffer to store encrypted data. * @return the buffer with encrypted data or null if don't need to decrypt encrypt. */ - @Nullable ByteBuffer encrypt(ByteBuffer data, int length, ByteBuffer toStore); + @Nullable + ByteBuffer encrypt(ByteBuffer data, int length, ByteBuffer toStore); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/NetworkFactory.java b/rlib-network/src/main/java/javasabr/rlib/network/NetworkFactory.java index ab1edeee..9d680070 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/NetworkFactory.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/NetworkFactory.java @@ -8,26 +8,28 @@ import javasabr.rlib.network.impl.DefaultConnection; import javasabr.rlib.network.impl.StringDataConnection; import javasabr.rlib.network.impl.StringDataSSLConnection; -import javasabr.rlib.network.packet.impl.DefaultReadablePacket; -import javasabr.rlib.network.packet.registry.ReadablePacketRegistry; +import javasabr.rlib.network.packet.impl.DefaultReadableNetworkPacket; +import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; import javasabr.rlib.network.server.ServerNetwork; import javasabr.rlib.network.server.impl.DefaultServerNetwork; import javax.net.ssl.SSLContext; +import lombok.experimental.UtilityClass; /** * Class with factory methods to build client/server networks. * * @author JavaSaBr */ +@UtilityClass public final class NetworkFactory { - public static > ClientNetwork newClientNetwork( + public static > ClientNetwork clientNetwork( NetworkConfig networkConfig, BiFunction, AsynchronousSocketChannel, C> channelToConnection) { return new DefaultClientNetwork<>(networkConfig, channelToConnection); } - public static > ServerNetwork newServerNetwork( + public static > ServerNetwork serverNetwork( ServerNetworkConfig networkConfig, BiFunction, AsynchronousSocketChannel, C> channelToConnection) { return new DefaultServerNetwork<>(networkConfig, channelToConnection); @@ -35,48 +37,36 @@ public final class NetworkFactory { /** * Create a string packet based asynchronous client network. - * - * @return the client network. */ - public static ClientNetwork newStringDataClientNetwork() { - return newStringDataClientNetwork(NetworkConfig.DEFAULT_CLIENT); + public static ClientNetwork stringDataClientNetwork() { + return stringDataClientNetwork(NetworkConfig.DEFAULT_CLIENT); } /** * Create a string packet based asynchronous client network. - * - * @param networkConfig the network config. - * @return the client network. */ - public static ClientNetwork newStringDataClientNetwork( + public static ClientNetwork stringDataClientNetwork( NetworkConfig networkConfig) { - return newStringDataClientNetwork(networkConfig, new DefaultBufferAllocator(networkConfig)); + return stringDataClientNetwork(networkConfig, new DefaultBufferAllocator(networkConfig)); } /** * Create a string packet based asynchronous client network. - * - * @param networkConfig the network config. - * @param bufferAllocator the buffer allocator. - * @return the client network. */ - public static ClientNetwork newStringDataClientNetwork( + public static ClientNetwork stringDataClientNetwork( NetworkConfig networkConfig, BufferAllocator bufferAllocator) { - return newClientNetwork( + return clientNetwork( networkConfig, (network, channel) -> new StringDataConnection(network, channel, bufferAllocator)); } /** * Create id based packet default asynchronous client network. - * - * @param packetRegistry the readable packet registry. - * @return the server network. */ - public static ClientNetwork newDefaultClientNetwork( - ReadablePacketRegistry packetRegistry) { - return newDefaultClientNetwork( + public static ClientNetwork defaultClientNetwork( + ReadableNetworkPacketRegistry packetRegistry) { + return defaultClientNetwork( NetworkConfig.DEFAULT_CLIENT, new DefaultBufferAllocator(NetworkConfig.DEFAULT_CLIENT), packetRegistry); @@ -84,17 +74,12 @@ public static ClientNetwork newDefaultClientNetwork( /** * Create id based packet default asynchronous client network. - * - * @param networkConfig the network config. - * @param bufferAllocator the buffer allocator. - * @param packetRegistry the readable packet registry. - * @return the server network. */ - public static ClientNetwork newDefaultClientNetwork( + public static ClientNetwork defaultClientNetwork( NetworkConfig networkConfig, BufferAllocator bufferAllocator, - ReadablePacketRegistry packetRegistry) { - return newClientNetwork( + ReadableNetworkPacketRegistry packetRegistry) { + return clientNetwork( networkConfig, (network, channel) -> new DefaultConnection(network, channel, bufferAllocator, packetRegistry)); } @@ -102,81 +87,60 @@ public static ClientNetwork newDefaultClientNetwork( /** * Create string packet based asynchronous secure client network. * - * @param networkConfig the network config. - * @param bufferAllocator the buffer allocator. - * @param sslContext the ssl context. - * @return the client network. */ - public static ClientNetwork newStringDataSSLClientNetwork( + public static ClientNetwork stringDataSslClientNetwork( NetworkConfig networkConfig, BufferAllocator bufferAllocator, SSLContext sslContext) { - return newClientNetwork( + return clientNetwork( networkConfig, (network, channel) -> new StringDataSSLConnection(network, channel, bufferAllocator, sslContext, true)); } /** * Create string packet based asynchronous server network. - * - * @return the server network. */ - public static ServerNetwork newStringDataServerNetwork() { - return newStringDataServerNetwork(ServerNetworkConfig.DEFAULT_SERVER); + public static ServerNetwork stringDataServerNetwork() { + return stringDataServerNetwork(ServerNetworkConfig.DEFAULT_SERVER); } /** * Create string packet based asynchronous server network. - * - * @param networkConfig the network config. - * @return the server network. */ - public static ServerNetwork newStringDataServerNetwork( + public static ServerNetwork stringDataServerNetwork( ServerNetworkConfig networkConfig) { - return newStringDataServerNetwork(networkConfig, new DefaultBufferAllocator(networkConfig)); + return stringDataServerNetwork(networkConfig, new DefaultBufferAllocator(networkConfig)); } /** * Create string packet based asynchronous server network. - * - * @param networkConfig the network config. - * @param bufferAllocator the buffer allocator. - * @return the server network. */ - public static ServerNetwork newStringDataServerNetwork( + public static ServerNetwork stringDataServerNetwork( ServerNetworkConfig networkConfig, BufferAllocator bufferAllocator) { - return newServerNetwork( + return serverNetwork( networkConfig, (network, channel) -> new StringDataConnection(network, channel, bufferAllocator)); } /** * Create string packet based asynchronous secure server network. - * - * @param networkConfig the network config. - * @param bufferAllocator the buffer allocator. - * @param sslContext the ssl context. - * @return the server network. */ - public static ServerNetwork newStringDataSSLServerNetwork( + public static ServerNetwork stringDataSslServerNetwork( ServerNetworkConfig networkConfig, BufferAllocator bufferAllocator, SSLContext sslContext) { - return newServerNetwork( + return serverNetwork( networkConfig, (network, channel) -> new StringDataSSLConnection(network, channel, bufferAllocator, sslContext, false)); } /** * Create id based packet default asynchronous server network. - * - * @param packetRegistry the readable packet registry. - * @return the server network. */ - public static ServerNetwork newDefaultServerNetwork( - ReadablePacketRegistry packetRegistry) { - return newDefaultServerNetwork( + public static ServerNetwork defaultServerNetwork( + ReadableNetworkPacketRegistry packetRegistry) { + return defaultServerNetwork( ServerNetworkConfig.DEFAULT_SERVER, new DefaultBufferAllocator(ServerNetworkConfig.DEFAULT_SERVER), packetRegistry); @@ -184,22 +148,13 @@ public static ServerNetwork newDefaultServerNetwork( /** * Create id based packet default asynchronous server network. - * - * @param networkConfig the network config. - * @param bufferAllocator the buffer allocator. - * @param packetRegistry the readable packet registry. - * @return the server network. */ - public static ServerNetwork newDefaultServerNetwork( + public static ServerNetwork defaultServerNetwork( ServerNetworkConfig networkConfig, BufferAllocator bufferAllocator, - ReadablePacketRegistry packetRegistry) { - return newServerNetwork( + ReadableNetworkPacketRegistry packetRegistry) { + return serverNetwork( networkConfig, (network, channel) -> new DefaultConnection(network, channel, bufferAllocator, packetRegistry)); } - - private NetworkFactory() throws Exception { - throw new Exception("no permission"); - } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/ServerNetworkConfig.java b/rlib-network/src/main/java/javasabr/rlib/network/ServerNetworkConfig.java index 9288365f..2a3711c0 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/ServerNetworkConfig.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/ServerNetworkConfig.java @@ -1,9 +1,10 @@ package javasabr.rlib.network; import java.nio.ByteOrder; -import javasabr.rlib.common.util.GroupThreadFactory; +import javasabr.rlib.common.util.GroupThreadFactory.ThreadConstructor; import lombok.Builder; import lombok.Getter; +import lombok.experimental.Accessors; /** * The interface to implement a server network config. @@ -14,6 +15,7 @@ public interface ServerNetworkConfig extends NetworkConfig { @Builder @Getter + @Accessors(fluent = true, chain = false) class SimpleServerNetworkConfig implements ServerNetworkConfig { @Builder.Default @@ -21,7 +23,7 @@ class SimpleServerNetworkConfig implements ServerNetworkConfig { @Builder.Default private ByteOrder byteOrder = ByteOrder.BIG_ENDIAN; @Builder.Default - private GroupThreadFactory.ThreadConstructor threadConstructor = Thread::new; + private ThreadConstructor threadConstructor = Thread::new; @Builder.Default private int readBufferSize = 2048; @@ -38,40 +40,34 @@ class SimpleServerNetworkConfig implements ServerNetworkConfig { ServerNetworkConfig DEFAULT_SERVER = new ServerNetworkConfig() { @Override - public int getThreadGroupMinSize() { + public int threadGroupMinSize() { return 1; } @Override - public String getThreadGroupName() { + public String threadGroupName() { return "ServerNetworkThread"; } }; /** * Get a minimal size of network thread executor. - * - * @return the minimal executor size. */ - default int getThreadGroupMinSize() { + default int threadGroupMinSize() { return 1; } /** * Get a maximum size of network thread executor. - * - * @return the maximum executor size. */ - default int getThreadGroupMaxSize() { - return getThreadGroupMinSize(); + default int threadGroupMaxSize() { + return threadGroupMinSize(); } /** * Get a thread constructor which should be used to create network threads. - * - * @return the thread constructor. */ - default GroupThreadFactory.ThreadConstructor getThreadConstructor() { + default ThreadConstructor threadConstructor() { return Thread::new; } @@ -80,7 +76,7 @@ default GroupThreadFactory.ThreadConstructor getThreadConstructor() { * * @return the priority of network threads. */ - default int getThreadPriority() { + default int threadPriority() { return Thread.NORM_PRIORITY; } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/UnsafeConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/UnsafeConnection.java index 3ab99e2b..7447fc97 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/UnsafeConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/UnsafeConnection.java @@ -1,10 +1,10 @@ package javasabr.rlib.network; -import javasabr.rlib.network.packet.ReadablePacket; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; -public interface UnsafeConnection extends Connection { +public interface UnsafeConnection + extends Connection { void onConnected(); - } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/annotation/PacketDescription.java b/rlib-network/src/main/java/javasabr/rlib/network/annotation/NetworkPacketDescription.java similarity index 90% rename from rlib-network/src/main/java/javasabr/rlib/network/annotation/PacketDescription.java rename to rlib-network/src/main/java/javasabr/rlib/network/annotation/NetworkPacketDescription.java index 48a8a37f..7c75856e 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/annotation/PacketDescription.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/annotation/NetworkPacketDescription.java @@ -14,7 +14,6 @@ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) -public @interface PacketDescription { - +public @interface NetworkPacketDescription { int id(); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/client/ClientNetwork.java b/rlib-network/src/main/java/javasabr/rlib/network/client/ClientNetwork.java index 836d28d7..e8a4b7ed 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/client/ClientNetwork.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/client/ClientNetwork.java @@ -1,6 +1,7 @@ package javasabr.rlib.network.client; import java.net.InetSocketAddress; +import java.util.Optional; import java.util.concurrent.CompletableFuture; import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; @@ -16,25 +17,27 @@ public interface ClientNetwork> extends Network { /** * Connect to a server by the address. - * - * @param serverAddress the sever address. - * @return the future with result connection. */ - CompletableFuture connect(InetSocketAddress serverAddress); + C connect(InetSocketAddress serverAddress); /** * Connect to a server by the address. - * - * @param serverAddress the sever address. - * @return the future with result connection. */ - Mono connected(InetSocketAddress serverAddress); + CompletableFuture connectAsync(InetSocketAddress serverAddress); + + /** + * Connect to a server by the address. + */ + Mono connectReactive(InetSocketAddress serverAddress); /** * Get a current connection to a server or null. - * - * @return the current connection or null. */ @Nullable - C getCurrentConnection(); + C currentConnection(); + + /** + * Get a current connection to a server or empty. + */ + Optional currentConnectionOptional(); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/client/impl/DefaultClientNetwork.java b/rlib-network/src/main/java/javasabr/rlib/network/client/impl/DefaultClientNetwork.java index 81f612a0..b682fed9 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/client/impl/DefaultClientNetwork.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/client/impl/DefaultClientNetwork.java @@ -1,9 +1,7 @@ package javasabr.rlib.network.client.impl; -import static javasabr.rlib.common.util.Utils.unchecked; -import static javasabr.rlib.common.util.Utils.uncheckedGet; - import java.net.InetSocketAddress; +import java.net.SocketAddress; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.Optional; @@ -12,15 +10,18 @@ import java.util.function.BiFunction; import javasabr.rlib.common.util.AsyncUtils; import javasabr.rlib.common.util.ThreadUtils; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; +import javasabr.rlib.common.util.Utils; import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; import javasabr.rlib.network.NetworkConfig; import javasabr.rlib.network.client.ClientNetwork; import javasabr.rlib.network.impl.AbstractNetwork; import javasabr.rlib.network.util.NetworkUtils; +import lombok.AccessLevel; +import lombok.CustomLog; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; import reactor.core.publisher.Mono; @@ -29,69 +30,69 @@ * * @author JavaSaBr */ +@CustomLog +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) public class DefaultClientNetwork> extends AbstractNetwork implements ClientNetwork { - protected static final Logger LOGGER = LoggerManager.getLogger(DefaultClientNetwork.class); + final AtomicBoolean connecting; - protected final AtomicBoolean connecting; + @Nullable + @Getter(AccessLevel.PROTECTED) + volatile CompletableFuture pendingConnection; - protected volatile @Nullable CompletableFuture pendingConnection; - protected volatile @Getter - @Nullable C currentConnection; + @Getter + @Nullable + volatile C currentConnection; public DefaultClientNetwork( NetworkConfig config, BiFunction, AsynchronousSocketChannel, C> channelToConnection) { super(config, channelToConnection); this.connecting = new AtomicBoolean(false); - - LOGGER.info( - config, - conf -> "Client network configuration: {\n" + " groupName: \"" + conf.getThreadGroupName() + "\",\n" - + " readBufferSize: " + conf.getReadBufferSize() + ",\n" + " pendingBufferSize: " - + conf.getPendingBufferSize() + ",\n" + " writeBufferSize: " + conf.getWriteBufferSize() + "\n" + "}"); + log.info(config, DefaultClientNetwork::buildConfigDescription); } @Override - public CompletableFuture connect(InetSocketAddress serverAddress) { + public C connect(InetSocketAddress serverAddress) { + return connectAsync(serverAddress).join(); + } - C currentConnection = getCurrentConnection(); + @Override + public CompletableFuture connectAsync(InetSocketAddress serverAddress) { + C currentConnection = currentConnection(); if (currentConnection != null) { - unchecked(currentConnection, C::close); + Utils.unchecked(currentConnection, C::close); } // if we are trying connection now if (!connecting.compareAndSet(false, true)) { - - var asyncResult = this.pendingConnection; - - if (asyncResult != null) { - return asyncResult; + CompletableFuture pendingConnection = pendingConnection(); + if (pendingConnection != null) { + return pendingConnection; } - ThreadUtils.sleep(100); - - return connect(serverAddress); + return connectAsync(serverAddress); } var asyncResult = new CompletableFuture(); - var channel = uncheckedGet(AsynchronousSocketChannel::open); - channel.connect( - serverAddress, null, new CompletionHandler() { - - @Override - public void completed(@Nullable Void result, @Nullable Void attachment) { - LOGGER.info(channel, ch -> "Connected to server: " + NetworkUtils.getRemoteAddress(ch)); - asyncResult.complete(channelToConnection.apply(DefaultClientNetwork.this, channel)); - } + @SuppressWarnings("resource") + var channel = Utils.uncheckedGet(AsynchronousSocketChannel::open); + channel.connect(serverAddress, this, new CompletionHandler<>() { + @Override + public void completed(@Nullable Void result, DefaultClientNetwork network) { + SocketAddress remoteAddress = NetworkUtils.getRemoteAddress(channel); + log.info(remoteAddress, "Connected to server:[%s]"::formatted); + asyncResult.complete(channelToConnection.apply(network, channel)); + } - @Override - public void failed(Throwable exc, @Nullable Void attachment) { - asyncResult.completeExceptionally(exc); - } - }); + @Override + public void failed(Throwable exc, DefaultClientNetwork attachment) { + asyncResult.completeExceptionally(exc); + } + }); pendingConnection = asyncResult; @@ -103,20 +104,34 @@ public void failed(Throwable exc, @Nullable Void attachment) { } @Override - public Mono connected(InetSocketAddress serverAddress) { - return Mono.create(monoSink -> connect(serverAddress).whenComplete((connection, ex) -> { - if (ex != null) { - monoSink.error(ex); - } else { - monoSink.success(connection); - } - })); + public Mono connectReactive(InetSocketAddress serverAddress) { + return Mono + .create(monoSink -> connectAsync(serverAddress) + .whenComplete((connection, ex) -> { + if (ex != null) { + monoSink.error(ex); + } else { + monoSink.success(connection); + } + })); + } + + @Override + public Optional currentConnectionOptional() { + return Optional.ofNullable(currentConnection()); } @Override public void shutdown() { - Optional - .ofNullable(getCurrentConnection()) - .ifPresent(connection -> unchecked(connection, C::close)); + C connection = currentConnection(); + if (connection != null) { + Utils.unchecked(connection, C::close); + } + } + + private static String buildConfigDescription(NetworkConfig conf) { + return "Client network configuration: {\n" + " groupName: \"" + conf.threadGroupName() + "\",\n" + + " readBufferSize: " + conf.readBufferSize() + ",\n" + " pendingBufferSize: " + conf.pendingBufferSize() + + ",\n" + " writeBufferSize: " + conf.writeBufferSize() + "\n" + "}"; } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java index 6928ea7a..de2764e5 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java @@ -18,10 +18,10 @@ import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; import javasabr.rlib.network.UnsafeConnection; -import javasabr.rlib.network.packet.PacketReader; -import javasabr.rlib.network.packet.PacketWriter; -import javasabr.rlib.network.packet.ReadablePacket; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.NetworkPacketReader; +import javasabr.rlib.network.packet.NetworkPacketWriter; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; import javasabr.rlib.network.packet.impl.WritablePacketWrapper; import javasabr.rlib.network.util.NetworkUtils; import lombok.Getter; @@ -34,12 +34,12 @@ * * @author JavaSaBr */ -public abstract class AbstractConnection implements +public abstract class AbstractConnection implements UnsafeConnection { private static final Logger LOGGER = LoggerManager.getLogger(AbstractConnection.class); - private static class WritablePacketWithFeedback extends + private static class WritablePacketWithFeedback extends WritablePacketWrapper, W> { public WritablePacketWithFeedback(CompletableFuture attachment, W packet) { @@ -53,7 +53,7 @@ public WritablePacketWithFeedback(CompletableFuture attachment, W packe protected final Network> network; protected final BufferAllocator bufferAllocator; protected final AsynchronousSocketChannel channel; - protected final Deque pendingPackets; + protected final Deque pendingPackets; protected final StampedLock lock; protected final AtomicBoolean isWriting; @@ -86,9 +86,9 @@ public AbstractConnection( public void onConnected() { } - protected abstract PacketReader getPacketReader(); + protected abstract NetworkPacketReader getPacketReader(); - protected abstract PacketWriter getPacketWriter(); + protected abstract NetworkPacketWriter getPacketWriter(); protected void handleReceivedPacket(R packet) { LOGGER.debug( @@ -138,7 +138,7 @@ protected void registerFluxOnReceivedPackets(FluxSink sink) { sink.onDispose(() -> subscribers.remove(listener)); } - protected @Nullable WritablePacket nextPacketToWrite() { + protected @Nullable WritableNetworkPacket nextPacketToWrite() { long stamp = lock.writeLock(); try { return pendingPackets.poll(); @@ -181,10 +181,10 @@ public boolean isClosed() { return closed.get(); } - protected void onWrittenPacket(WritablePacket packet) { + protected void onWrittenPacket(WritableNetworkPacket packet) { } - protected void onSentPacket(WritablePacket packet, Boolean result) { + protected void onSentPacket(WritableNetworkPacket packet, Boolean result) { if (packet instanceof WritablePacketWithFeedback) { ((WritablePacketWithFeedback) packet) .getAttachment() @@ -197,7 +197,7 @@ public final void send(W packet) { sendImpl(packet); } - protected void sendImpl(WritablePacket packet) { + protected void sendImpl(WritableNetworkPacket packet) { if (isClosed()) { return; @@ -213,7 +213,7 @@ protected void sendImpl(WritablePacket packet) { getPacketWriter().writeNextPacket(); } - protected void queueAtFirst(WritablePacket packet) { + protected void queueAtFirst(WritableNetworkPacket packet) { long stamp = lock.writeLock(); try { pendingPackets.addFirst(packet); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractNetwork.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractNetwork.java index d2b8e76a..592fc997 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractNetwork.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractNetwork.java @@ -2,28 +2,23 @@ import java.nio.channels.AsynchronousSocketChannel; import java.util.function.BiFunction; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; import javasabr.rlib.network.NetworkConfig; +import lombok.AccessLevel; +import lombok.CustomLog; +import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; /** * The base implementation of {@link Network}. * * @author JavaSaBr */ +@CustomLog +@RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public abstract class AbstractNetwork> implements Network { - - protected static final Logger LOGGER = LoggerManager.getLogger(AbstractNetwork.class); - - protected final NetworkConfig config; - protected final BiFunction, AsynchronousSocketChannel, C> channelToConnection; - - protected AbstractNetwork( - NetworkConfig config, - BiFunction, AsynchronousSocketChannel, C> channelToConnection) { - this.config = config; - this.channelToConnection = channelToConnection; - } + NetworkConfig config; + BiFunction, AsynchronousSocketChannel, C> channelToConnection; } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSSLConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSSLConnection.java index 80a4ae16..31bcc1aa 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSSLConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSSLConnection.java @@ -4,13 +4,13 @@ import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; -import javasabr.rlib.network.packet.ReadablePacket; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; -public abstract class AbstractSSLConnection extends +public abstract class AbstractSSLConnection extends AbstractConnection { protected final SSLEngine sslEngine; @@ -33,7 +33,7 @@ public AbstractSSLConnection( } @Override - protected void sendImpl(WritablePacket packet) { + protected void sendImpl(WritableNetworkPacket packet) { super.sendImpl(packet); getPacketReader().startRead(); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultConnection.java index c14df701..1d1f597b 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultConnection.java @@ -4,20 +4,20 @@ import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; -import javasabr.rlib.network.packet.impl.DefaultReadablePacket; -import javasabr.rlib.network.packet.impl.DefaultWritablePacket; -import javasabr.rlib.network.packet.registry.ReadablePacketRegistry; +import javasabr.rlib.network.packet.impl.DefaultReadableNetworkPacket; +import javasabr.rlib.network.packet.impl.DefaultWritableNetworkPacket; +import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; /** * @author JavaSaBr */ -public class DefaultConnection extends IdBasedPacketConnection { +public class DefaultConnection extends IdBasedPacketConnection { public DefaultConnection( - Network> network, + Network> network, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, - ReadablePacketRegistry packetRegistry) { + ReadableNetworkPacketRegistry packetRegistry) { super(network, channel, bufferAllocator, packetRegistry, 100, 2, 2); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataConnection.java index c9146330..87156783 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataConnection.java @@ -4,12 +4,12 @@ import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; -import javasabr.rlib.network.packet.PacketReader; -import javasabr.rlib.network.packet.PacketWriter; -import javasabr.rlib.network.packet.ReadablePacket; -import javasabr.rlib.network.packet.WritablePacket; -import javasabr.rlib.network.packet.impl.DefaultPacketReader; -import javasabr.rlib.network.packet.impl.DefaultPacketWriter; +import javasabr.rlib.network.packet.NetworkPacketReader; +import javasabr.rlib.network.packet.NetworkPacketWriter; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; +import javasabr.rlib.network.packet.impl.DefaultNetworkPacketReader; +import javasabr.rlib.network.packet.impl.DefaultNetworkPacketWriter; import lombok.AccessLevel; import lombok.Getter; @@ -17,11 +17,11 @@ * @author JavaSaBr */ @Getter(AccessLevel.PROTECTED) -public abstract class DefaultDataConnection extends +public abstract class DefaultDataConnection extends AbstractConnection { - private final PacketReader packetReader; - private final PacketWriter packetWriter; + private final NetworkPacketReader packetReader; + private final NetworkPacketWriter packetWriter; private final int packetLengthHeaderSize; @@ -37,8 +37,8 @@ public DefaultDataConnection( this.packetWriter = createPacketWriter(); } - protected PacketReader createPacketReader() { - return new DefaultPacketReader<>( + protected NetworkPacketReader createPacketReader() { + return new DefaultNetworkPacketReader<>( this, channel, bufferAllocator, @@ -49,8 +49,8 @@ protected PacketReader createPacketReader() { maxPacketsByRead); } - protected PacketWriter createPacketWriter() { - return new DefaultPacketWriter>( + protected NetworkPacketWriter createPacketWriter() { + return new DefaultNetworkPacketWriter>( this, channel, bufferAllocator, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSSLConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSSLConnection.java index 283220d2..7044b892 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSSLConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSSLConnection.java @@ -4,12 +4,12 @@ import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; -import javasabr.rlib.network.packet.PacketReader; -import javasabr.rlib.network.packet.PacketWriter; -import javasabr.rlib.network.packet.ReadablePacket; -import javasabr.rlib.network.packet.WritablePacket; -import javasabr.rlib.network.packet.impl.DefaultSSLPacketReader; -import javasabr.rlib.network.packet.impl.DefaultSSLPacketWriter; +import javasabr.rlib.network.packet.NetworkPacketReader; +import javasabr.rlib.network.packet.NetworkPacketWriter; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; +import javasabr.rlib.network.packet.impl.DefaultSslNetworkPacketReader; +import javasabr.rlib.network.packet.impl.DefaultSslNetworkPacketWriter; import javax.net.ssl.SSLContext; import lombok.AccessLevel; import lombok.Getter; @@ -18,11 +18,11 @@ * @author JavaSaBr */ @Getter(AccessLevel.PROTECTED) -public abstract class DefaultDataSSLConnection extends +public abstract class DefaultDataSSLConnection extends AbstractSSLConnection { - private final PacketReader packetReader; - private final PacketWriter packetWriter; + private final NetworkPacketReader packetReader; + private final NetworkPacketWriter packetWriter; private final int packetLengthHeaderSize; @@ -40,8 +40,8 @@ public DefaultDataSSLConnection( this.packetWriter = createPacketWriter(); } - protected PacketReader createPacketReader() { - return new DefaultSSLPacketReader<>( + protected NetworkPacketReader createPacketReader() { + return new DefaultSslNetworkPacketReader<>( this, channel, bufferAllocator, @@ -54,8 +54,8 @@ protected PacketReader createPacketReader() { maxPacketsByRead); } - protected PacketWriter createPacketWriter() { - return new DefaultSSLPacketWriter>( + protected NetworkPacketWriter createPacketWriter() { + return new DefaultSslNetworkPacketWriter>( this, channel, bufferAllocator, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/IdBasedPacketConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/IdBasedPacketConnection.java index 3f98fa0b..8584f93e 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/IdBasedPacketConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/IdBasedPacketConnection.java @@ -4,13 +4,13 @@ import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; -import javasabr.rlib.network.packet.IdBasedReadablePacket; -import javasabr.rlib.network.packet.IdBasedWritablePacket; -import javasabr.rlib.network.packet.PacketReader; -import javasabr.rlib.network.packet.PacketWriter; +import javasabr.rlib.network.packet.IdBasedReadableNetworkPacket; +import javasabr.rlib.network.packet.IdBasedWritableNetworkPacket; +import javasabr.rlib.network.packet.NetworkPacketReader; +import javasabr.rlib.network.packet.NetworkPacketWriter; import javasabr.rlib.network.packet.impl.IdBasedPacketReader; -import javasabr.rlib.network.packet.impl.IdBasedPacketWriter; -import javasabr.rlib.network.packet.registry.ReadablePacketRegistry; +import javasabr.rlib.network.packet.impl.IdBasedNetworkPacketWriter; +import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; import lombok.AccessLevel; import lombok.Getter; @@ -18,12 +18,12 @@ * @author JavaSaBr */ @Getter(AccessLevel.PROTECTED) -public class IdBasedPacketConnection, W extends IdBasedWritablePacket> extends +public class IdBasedPacketConnection, W extends IdBasedWritableNetworkPacket> extends AbstractConnection { - private final PacketReader packetReader; - private final PacketWriter packetWriter; - private final ReadablePacketRegistry packetRegistry; + private final NetworkPacketReader packetReader; + private final NetworkPacketWriter packetWriter; + private final ReadableNetworkPacketRegistry packetRegistry; private final int packetLengthHeaderSize; private final int packetIdHeaderSize; @@ -32,7 +32,7 @@ public IdBasedPacketConnection( Network> network, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, - ReadablePacketRegistry packetRegistry, + ReadableNetworkPacketRegistry packetRegistry, int maxPacketsByRead, int packetLengthHeaderSize, int packetIdHeaderSize) { @@ -44,7 +44,7 @@ public IdBasedPacketConnection( this.packetWriter = createPacketWriter(); } - protected PacketReader createPacketReader() { + protected NetworkPacketReader createPacketReader() { return new IdBasedPacketReader<>( this, channel, @@ -57,8 +57,8 @@ protected PacketReader createPacketReader() { packetRegistry); } - protected PacketWriter createPacketWriter() { - return new IdBasedPacketWriter<>( + protected NetworkPacketWriter createPacketWriter() { + return new IdBasedNetworkPacketWriter<>( this, channel, bufferAllocator, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataConnection.java index cbad855b..52d61ea9 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataConnection.java @@ -5,15 +5,15 @@ import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; import javasabr.rlib.network.packet.impl.StringReadablePacket; -import javasabr.rlib.network.packet.impl.StringWritablePacket; +import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; /** * @author JavaSaBr */ -public class StringDataConnection extends DefaultDataConnection { +public class StringDataConnection extends DefaultDataConnection { public StringDataConnection( - Network> network, + Network> network, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator) { super(network, channel, bufferAllocator, 100, 2); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSSLConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSSLConnection.java index e07e5050..2a2aa617 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSSLConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSSLConnection.java @@ -5,16 +5,16 @@ import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; import javasabr.rlib.network.packet.impl.StringReadablePacket; -import javasabr.rlib.network.packet.impl.StringWritablePacket; +import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; import javax.net.ssl.SSLContext; /** * @author JavaSaBr */ -public class StringDataSSLConnection extends DefaultDataSSLConnection { +public class StringDataSSLConnection extends DefaultDataSSLConnection { public StringDataSSLConnection( - Network> network, + Network> network, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, SSLContext sslContext, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedNetworkPacket.java new file mode 100644 index 00000000..cf32dfd3 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedNetworkPacket.java @@ -0,0 +1,20 @@ +package javasabr.rlib.network.packet; + +import javasabr.rlib.network.annotation.NetworkPacketDescription; + +/** + * @author JavaSaBr + */ +public interface IdBasedNetworkPacket extends NetworkPacket { + + /** + * Get id of this packet. + * + * @return the packet type's id. + */ + default int packetId() { + return getClass() + .getAnnotation(NetworkPacketDescription.class) + .id(); + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedPacket.java deleted file mode 100644 index 7be950ab..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedPacket.java +++ /dev/null @@ -1,20 +0,0 @@ -package javasabr.rlib.network.packet; - -import javasabr.rlib.network.annotation.PacketDescription; - -/** - * @author JavaSaBr - */ -public interface IdBasedPacket extends Packet { - - /** - * Get id of this packet. - * - * @return the packet type's id. - */ - default int getPacketId() { - return getClass() - .getAnnotation(PacketDescription.class) - .id(); - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedReadableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedReadableNetworkPacket.java new file mode 100644 index 00000000..9f3fa344 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedReadableNetworkPacket.java @@ -0,0 +1,18 @@ +package javasabr.rlib.network.packet; + +import javasabr.rlib.common.util.ClassUtils; +import javasabr.rlib.network.Connection; + +/** + * @author JavaSaBr + */ +public interface IdBasedReadableNetworkPacket> + extends ReadableNetworkPacket, IdBasedNetworkPacket { + + /** + * Create a new instance of this type. + */ + default S newInstance() { + return ClassUtils.newInstance(getClass()); + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedReadablePacket.java deleted file mode 100644 index ee45a273..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedReadablePacket.java +++ /dev/null @@ -1,28 +0,0 @@ -package javasabr.rlib.network.packet; - -import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.network.Connection; - -/** - * @author JavaSaBr - */ -public interface IdBasedReadablePacket> extends ReadablePacket, IdBasedPacket { - - /** - * Create a new instance of this type. - * - * @return the new instance of this type. - */ - default S newInstance() { - return ClassUtils.newInstance(getClass()); - } - - /** - * Execute a logic of this packet. - * - * @param connection the owner's connection. - */ - default void execute(Connection connection) { - - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedWritableNetworkPacket.java new file mode 100644 index 00000000..d157e6eb --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedWritableNetworkPacket.java @@ -0,0 +1,7 @@ +package javasabr.rlib.network.packet; + +/** + * @author JavaSaBr + */ +public interface IdBasedWritableNetworkPacket extends WritableNetworkPacket, IdBasedNetworkPacket { +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedWritablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedWritablePacket.java deleted file mode 100644 index 2907a2e6..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/IdBasedWritablePacket.java +++ /dev/null @@ -1,8 +0,0 @@ -package javasabr.rlib.network.packet; - -/** - * @author JavaSaBr - */ -public interface IdBasedWritablePacket extends WritablePacket, IdBasedPacket { - -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/MarkerNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/MarkerNetworkPacket.java new file mode 100644 index 00000000..fe98047c --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/MarkerNetworkPacket.java @@ -0,0 +1,6 @@ +package javasabr.rlib.network.packet; + +/** + * Interface to mark that some specific packet doesn't have any data. + */ +public interface MarkerNetworkPacket {} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/Packet.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacket.java similarity index 68% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/Packet.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacket.java index 8be12d1c..5ee76d47 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/Packet.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacket.java @@ -5,12 +5,10 @@ * * @author JavaSaBr */ -public interface Packet { +public interface NetworkPacket { /** - * Get packet's name. - * * @return the packet's name. */ - String getName(); + String name(); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/PacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketReader.java similarity index 84% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/PacketReader.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketReader.java index 1940e916..6111320f 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/PacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketReader.java @@ -3,7 +3,7 @@ /** * @author JavaSaBr */ -public interface PacketReader { +public interface NetworkPacketReader { /** * Activate a process of receiving packets. diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/PacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketWriter.java similarity index 80% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/PacketWriter.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketWriter.java index db1d428c..ecaedef1 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/PacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketWriter.java @@ -3,7 +3,7 @@ /** * @author JavaSaBr */ -public interface PacketWriter { +public interface NetworkPacketWriter { void writeNextPacket(); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/ReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/ReadableNetworkPacket.java similarity index 55% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/ReadablePacket.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/ReadableNetworkPacket.java index 58eab190..9816e686 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/ReadablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/ReadableNetworkPacket.java @@ -1,22 +1,20 @@ package javasabr.rlib.network.packet; import java.nio.ByteBuffer; -import javasabr.rlib.network.Connection; /** * The interface to implement a readable network packet. * * @author JavaSaBr */ -public interface ReadablePacket extends Packet { +public interface ReadableNetworkPacket extends NetworkPacket { /** * Read packet's data from byte buffer. * - * @param connection the network connection. * @param buffer the buffer with received data. - * @param length the data length. + * @param expectedLength the expected data length. * @return true if reading was success. */ - boolean read(Connection connection, ByteBuffer buffer, int length); + boolean read(ByteBuffer buffer, int expectedLength); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/ReusableWritablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/ReusableWritablePacket.java index b4eb1b06..bfbc96ba 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/ReusableWritablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/ReusableWritablePacket.java @@ -8,7 +8,7 @@ * * @author JavaSaBr */ -public interface ReusableWritablePacket extends WritablePacket, Reusable { +public interface ReusableWritablePacket extends WritableNetworkPacket, Reusable { /** * Handle completion of packet sending. diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/WritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/WritableNetworkPacket.java new file mode 100644 index 00000000..d966e82b --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/WritableNetworkPacket.java @@ -0,0 +1,25 @@ +package javasabr.rlib.network.packet; + +import java.nio.ByteBuffer; + +/** + * Interface to implement a writable packet. + * + * @author JavaSaBr + */ +public interface WritableNetworkPacket extends NetworkPacket { + + /** + * Write this packet to the buffer. + * + * @return true if writing was successful. + */ + boolean write(ByteBuffer buffer); + + /** + * @return expected data length of this packet or -1. + */ + default int expectedLength() { + return -1; + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/WritablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/WritablePacket.java deleted file mode 100644 index cf392115..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/WritablePacket.java +++ /dev/null @@ -1,135 +0,0 @@ -package javasabr.rlib.network.packet; - -import java.nio.BufferOverflowException; -import java.nio.ByteBuffer; -import javasabr.rlib.logger.api.LoggerManager; - -/** - * Interface to implement a writable packet. - * - * @author JavaSaBr - */ -public interface WritablePacket extends Packet { - - /** - * Write this packet to the buffer. - * - * @param buffer the buffer. - * @return true if writing was successful. - */ - boolean write(ByteBuffer buffer); - - /** - * Return an expected data length of this packet or -1. - * - * @return expected data length of this packet or -1. - */ - default int getExpectedLength() { - return -1; - } - - /** - * Write 1 byte to the buffer. - * - * @param buffer the buffer. - * @param value the value. - */ - default void writeByte(ByteBuffer buffer, int value) { - buffer.put((byte) value); - } - - /** - * Write 2 bytes to the buffer. - * - * @param buffer the buffer. - * @param value the value. - */ - default void writeChar(ByteBuffer buffer, char value) { - buffer.putChar(value); - } - - /** - * Write 2 bytes to the buffer. - * - * @param buffer the buffer. - * @param value the value. - */ - default void writeChar(final ByteBuffer buffer, final int value) { - buffer.putChar((char) value); - } - - /** - * Write 4 bytes to the buffer. - * - * @param buffer the buffer. - * @param value the value. - */ - default void writeFloat(ByteBuffer buffer, float value) { - buffer.putFloat(value); - } - - /** - * Write 4 bytes to the buffer. - * - * @param buffer the buffer. - * @param value the value. - */ - default void writeInt(ByteBuffer buffer, int value) { - buffer.putInt(value); - } - - /** - * Write 8 bytes to the buffer. - * - * @param buffer the buffer. - * @param value the value. - */ - default void writeLong(ByteBuffer buffer, long value) { - buffer.putLong(value); - } - - /** - * Writes 2 bytes to the buffer. - * - * @param buffer the buffer. - * @param value the value for writing. - */ - default void writeShort(ByteBuffer buffer, int value) { - buffer.putShort((short) value); - } - - /** - * Writes the string to the buffer. - * - * @param buffer the buffer. - * @param string the string for writing. - */ - default void writeString(ByteBuffer buffer, String string) { - try { - - writeInt(buffer, string.length()); - - for (int i = 0, length = string.length(); i < length; i++) { - buffer.putChar(string.charAt(i)); - } - - } catch (BufferOverflowException ex) { - LoggerManager - .getLogger(WritablePacket.class) - .error( - "Cannot write a string to buffer because the string is too long." + " String length: " + string.length() - + ", buffer: " + buffer); - throw ex; - } - } - - /** - * Write a data buffer to packet buffer. - * - * @param buffer thr packet buffer. - * @param data the data buffer. - */ - default void writeBuffer(ByteBuffer buffer, ByteBuffer data) { - buffer.put(data.array(), data.position(), data.limit()); - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractIdBasedReadableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractIdBasedReadableNetworkPacket.java new file mode 100644 index 00000000..0c57eeef --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractIdBasedReadableNetworkPacket.java @@ -0,0 +1,10 @@ +package javasabr.rlib.network.packet.impl; + +import javasabr.rlib.network.packet.IdBasedReadableNetworkPacket; + +/** + * @author JavaSaBr + */ +public abstract class AbstractIdBasedReadableNetworkPacket> + extends AbstractReadableNetworkPacket implements IdBasedReadableNetworkPacket { +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractIdBasedReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractIdBasedReadablePacket.java deleted file mode 100644 index c3202d4e..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractIdBasedReadablePacket.java +++ /dev/null @@ -1,29 +0,0 @@ -package javasabr.rlib.network.packet.impl; - -import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.IdBasedReadablePacket; - -/** - * @author JavaSaBr - */ -public abstract class AbstractIdBasedReadablePacket, - S extends AbstractIdBasedReadablePacket> extends - AbstractReadablePacket implements IdBasedReadablePacket { - - private static final Logger LOGGER = LoggerManager.getLogger(AbstractIdBasedReadablePacket.class); - - @Override - public void execute(Connection connection) { - try { - executeImpl(ClassUtils.unsafeNNCast(connection)); - } catch (Exception e) { - LOGGER.error(e); - } - } - - protected void executeImpl(C connection) { - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java new file mode 100644 index 00000000..0be827ba --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java @@ -0,0 +1,48 @@ +package javasabr.rlib.network.packet.impl; + +import static javasabr.rlib.network.util.NetworkUtils.hexDump; + +import java.nio.ByteBuffer; +import javasabr.rlib.network.packet.NetworkPacket; +import lombok.CustomLog; + +/** + * The base implementation of {@link NetworkPacket}. + * + * @author JavaSaBr + */ +@CustomLog +public abstract class AbstractNetworkPacket implements NetworkPacket { + + /** + * Handles packet data exception. + */ + protected void handleException(ByteBuffer buffer, Exception exception) { + log.warning(exception); + if (!log.warningEnabled()) { + return; + } + + String hexDump; + + if (buffer.isDirect()) { + var array = new byte[buffer.limit()]; + buffer.get(array, 0, buffer.limit()); + hexDump = hexDump(array, array.length); + } else { + hexDump = hexDump(buffer.array(), buffer.limit()); + } + + log.warning(name(), buffer, hexDump, "[%s] -> buffer:[%s]\n[%s]"::formatted); + } + + @Override + public String name() { + return getClass().getSimpleName(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{" + "name='" + name() + '\'' + '}'; + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java new file mode 100644 index 00000000..f87dbcd6 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java @@ -0,0 +1,417 @@ +package javasabr.rlib.network.packet.impl; + +import static javasabr.rlib.common.util.ObjectUtils.notNull; + +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousCloseException; +import java.nio.channels.AsynchronousSocketChannel; +import java.nio.channels.CompletionHandler; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; +import javasabr.rlib.common.util.BufferUtils; +import javasabr.rlib.network.BufferAllocator; +import javasabr.rlib.network.Connection; +import javasabr.rlib.network.packet.NetworkPacketReader; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import javasabr.rlib.network.util.NetworkUtils; +import lombok.AccessLevel; +import lombok.CustomLog; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; + +/** + * @param the readable packet's type. + * @param the connection's type. + * @author JavaSaBr + */ +@CustomLog +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractNetworkPacketReader> + implements NetworkPacketReader { + + final CompletionHandler readChannelHandler = new CompletionHandler<>() { + + @Override + public void completed(Integer receivedBytes, ByteBuffer readingBuffer) { + handleReceivedData(receivedBytes, readingBuffer); + } + + @Override + public void failed(Throwable exc, ByteBuffer readingBuffer) { + handleFailedReceiving(exc, readingBuffer); + } + }; + + final AtomicBoolean reading = new AtomicBoolean(false); + + final C connection; + final AsynchronousSocketChannel socketChannel; + final BufferAllocator bufferAllocator; + + final ByteBuffer readBuffer; + final ByteBuffer pendingBuffer; + + final Runnable updateActivityFunction; + final Consumer packetHandler; + + @Getter(AccessLevel.PROTECTED) + @Setter(AccessLevel.PROTECTED) + @Nullable + volatile ByteBuffer tempBigBuffer; + + final int maxPacketsByRead; + + protected AbstractNetworkPacketReader( + C connection, + AsynchronousSocketChannel socketChannel, + BufferAllocator bufferAllocator, + Runnable updateActivityFunction, + Consumer packetHandler, + int maxPacketsByRead) { + this.connection = connection; + this.socketChannel = socketChannel; + this.bufferAllocator = bufferAllocator; + this.readBuffer = bufferAllocator.takeReadBuffer(); + this.pendingBuffer = bufferAllocator.takePendingBuffer(); + this.updateActivityFunction = updateActivityFunction; + this.packetHandler = packetHandler; + this.maxPacketsByRead = maxPacketsByRead; + } + + protected ByteBuffer bufferToReadFromChannel() { + return readBuffer; + } + + @Override + public void startRead() { + if (!reading.compareAndSet(false, true)) { + return; + } + log.debug(socketChannel, ch -> "Start waiting for new data from channel:[" + NetworkUtils.getRemoteAddress(ch) + "]"); + ByteBuffer buffer = bufferToReadFromChannel(); + socketChannel.read(buffer, buffer, readChannelHandler); + } + + /** + * Reads packets from the buffer with received data. + * + * @param receivedBuffer the buffer with received data. + * @return count of read packets. + */ + protected int readPackets(ByteBuffer receivedBuffer) { + return readPackets(receivedBuffer, pendingBuffer); + } + + /** + * Reads packets from the buffer with received data. + * + * @param receivedBuffer the buffer with received data. + * @param pendingBuffer the buffer with pending data from prev. received buffer. + * @return count of read packets. + */ + protected int readPackets(ByteBuffer receivedBuffer, ByteBuffer pendingBuffer) { + log.debug(receivedBuffer, "Start reading packets from received buffer:[%s]"::formatted); + + int waitedBytes = pendingBuffer.position(); + ByteBuffer bufferToRead = receivedBuffer; + ByteBuffer tempBigBuffer = tempBigBuffer(); + + // if we have a temp big buffer it means that we are reading a big packet now + if (tempBigBuffer != null) { + // check and extends temp buffer if need + if (tempBigBuffer.remaining() < receivedBuffer.remaining()) { + reAllocTempBigBuffers(tempBigBuffer.flip(), tempBigBuffer.capacity()); + tempBigBuffer = notNull(tempBigBuffer()); + } + + log.debug(receivedBuffer, tempBigBuffer, "Put received buffer:[%s] to temp big buffer:[%s]"::formatted); + bufferToRead = BufferUtils.putToAndFlip(tempBigBuffer, receivedBuffer); + } + // if we have some pending data we need to append the received buffer to the pending buffer + // and start to read pending buffer with result received data + else if (waitedBytes > 0) { + if (pendingBuffer.remaining() < receivedBuffer.remaining()) { + log.debug( + pendingBuffer, + receivedBuffer, + "Pending buffer:[%s] is too small to append received buffer:[%s], allocate new temp bug buffer for this"::formatted); + + allocTempBigBuffers(pendingBuffer.flip(), pendingBuffer.capacity()); + + log.debug(pendingBuffer, "Clear pending buffer:[%s]"::formatted); + pendingBuffer.clear(); + + tempBigBuffer = notNull(tempBigBuffer()); + + log.debug(receivedBuffer, tempBigBuffer, "Put received buffer:[%s] to temp big buffer:[%s]"::formatted); + bufferToRead = BufferUtils.putToAndFlip(tempBigBuffer, receivedBuffer); + } else { + log.debug(receivedBuffer, pendingBuffer, "Put received buffer:[%s] to pending buffer:[%s]"::formatted); + bufferToRead = BufferUtils.putToAndFlip(pendingBuffer, receivedBuffer); + } + } + + int maxPacketsByRead = maxPacketsByRead(); + int readPackets = 0; + int endPosition = 0; + + while (canStartReadPacket(bufferToRead) && readPackets < maxPacketsByRead) { + // set position to start reading a next packet + bufferToRead.position(endPosition); + + int positionBeforeRead = endPosition; + int alreadyReadBytes = bufferToRead.position() - endPosition; + int packetFullLength = readFullPacketLength(bufferToRead); + int packetDataLength = calculatePacketDataLength(packetFullLength, alreadyReadBytes, bufferToRead); + + log.debug(positionBeforeRead, packetFullLength, "Found next packet from position:[%s] with length:[%s] "::formatted); + + // calculate position of the end of next packet + endPosition += packetFullLength; + + // if the packet isn't full presented in this buffer + if (packetFullLength == -1 || endPosition > bufferToRead.limit()) { + bufferToRead.position(positionBeforeRead); + + // if we read the received buffer we need to put not yet read data to the pending + // buffer or temp big buffer + if (bufferToRead == receivedBuffer) { + if (packetFullLength <= pendingBuffer.capacity()) { + pendingBuffer.put(receivedBuffer); + log.debug(pendingBuffer, "Put pending data form received buffer to pending buffer:[%s]"::formatted); + } else { + allocTempBigBuffers(receivedBuffer, packetFullLength); + } + } + // if we already read this pending buffer we need to compact it + else if (bufferToRead == pendingBuffer) { + if (packetFullLength <= pendingBuffer.capacity()) { + pendingBuffer.compact(); + log.debug(pendingBuffer, "Compact pending buffer:[%s]"::formatted); + } else { + allocTempBigBuffers(pendingBuffer, packetFullLength); + log.debug(pendingBuffer, "Clear pending buffer:[%s]"::formatted); + pendingBuffer.clear(); + } + + } else if (bufferToRead == tempBigBuffer) { + // if not yet read data is less than pending buffer, then we can switch to use the pending buffer + if (Math.max(packetFullLength, tempBigBuffer.remaining()) <= pendingBuffer.capacity()) { + pendingBuffer.clear().put(tempBigBuffer); + log.debug(pendingBuffer, "Moved pending data from temp big buffer to pending buffer:[%s]"::formatted); + freeTempBigBuffers(); + } + // if a new packet is bigger than current temp big buffer + else if (packetFullLength > tempBigBuffer.capacity()) { + reAllocTempBigBuffers(tempBigBuffer, packetFullLength); + } + // or just compact this current temp big buffer + else { + tempBigBuffer.compact(); + log.debug(tempBigBuffer, "Compact temp big buffer:[%s]]"::formatted); + } + } + + log.debug( + readPackets, + connection.remoteAddress(), + ("Read [%s] packets from received buffer of [%s], " + + "but 1 packet is still waiting for receiving additional data.")::formatted); + + receivedBuffer.clear(); + return readPackets; + } + + R readablePacket = createPacketFor( + bufferToRead, + positionBeforeRead, + packetFullLength, + packetDataLength); + + if (readablePacket != null) { + log.debug(readablePacket, "Created instance of packet to read data:[%s]"::formatted); + readAndHandlePacket(bufferToRead, packetDataLength, readablePacket); + log.debug(readablePacket, "Finished reading data for packet:[%s]"::formatted); + readPackets++; + } else { + log.warning("Cannot create any instance of packet to read data"); + } + + bufferToRead.position(endPosition); + } + + if (bufferToRead.hasRemaining()) { + if (bufferToRead == receivedBuffer) { + pendingBuffer.put(receivedBuffer); + log.debug("Found not yet read data from receive buffer, will put it to pending buffer."); + } else { + bufferToRead.compact(); + } + } else if (bufferToRead == pendingBuffer) { + pendingBuffer.clear(); + } else if (tempBigBuffer != null) { + freeTempBigBuffers(); + } + + log.debug(readPackets, connection.remoteAddress(), "Read [%s] packets from received buffer of [%s]"::formatted); + receivedBuffer.clear(); + return readPackets; + } + + protected void readAndHandlePacket(ByteBuffer bufferToRead, int packetDataLength, R packetInstance) { + if (packetInstance.read(bufferToRead, packetDataLength)) { + packetHandler.accept(packetInstance); + } else { + log.error(packetInstance, "Packet:[%s] was read incorrectly"::formatted); + } + } + + /** + * Checks the buffer's data. + * + * @return true if this buffer has enough data to start initial reading. + */ + protected abstract boolean canStartReadPacket(ByteBuffer buffer); + + /** + * Calculates size of packet data. + * + * @param packetLength the full packet length. + * @param alreadyReadBytes the count of already read bytes from buffer to get packet length. + * @param buffer the data buffer. + * @return the length of packet data part. + */ + protected int calculatePacketDataLength(int packetLength, int alreadyReadBytes, ByteBuffer buffer) { + return packetLength - alreadyReadBytes; + } + + /** + * Gets the packet's full length of next packet in the buffer. + * + * @param buffer the buffer with received data. + * @return the packet length or -1 if we have no enough data to read length. + */ + protected abstract int readFullPacketLength(ByteBuffer buffer); + + protected void reAllocTempBigBuffers(ByteBuffer sourceBuffer, int fullPacketLength) { + log.debug(sourceBuffer.capacity(), fullPacketLength, "Resize temp big buffer from:[%s] to:[%s]"::formatted); + + var newTempBuffer = bufferAllocator.takeBuffer(fullPacketLength + readBuffer.capacity()); + log.debug(sourceBuffer, newTempBuffer, "Moved data from old temp big buffer:[%s] to new:[%s]"::formatted); + newTempBuffer.put(sourceBuffer); + + freeTempBigBuffers(); + this.tempBigBuffer = newTempBuffer; + } + + protected void allocTempBigBuffers(ByteBuffer sourceBuffer, int fullPacketLength) { + int notConsumeBytes = sourceBuffer.remaining(); + log.debug( + notConsumeBytes, + fullPacketLength, + "Request temp big buffer to store part:[%s] of big packet with length:[%s]"::formatted); + + var tempBigBuffer = bufferAllocator.takeBuffer(fullPacketLength + readBuffer.capacity()); + log.debug(sourceBuffer, tempBigBuffer, "Put data from old temp big buffer:[%s] to new:[%s]"::formatted); + tempBigBuffer.put(sourceBuffer); + + this.tempBigBuffer = tempBigBuffer; + } + + protected void freeTempBigBuffers() { + ByteBuffer tempBuffer = tempBigBuffer(); + if (tempBuffer != null) { + tempBigBuffer(null); + bufferAllocator.putBuffer(tempBuffer); + } + } + + /** + * Handles received data from the channel. + */ + protected void handleReceivedData(Integer receivedBytes, ByteBuffer readingBuffer) { + updateActivityFunction.run(); + + if (receivedBytes == -1) { + connection.close(); + return; + } + + log.debug(receivedBytes, connection.remoteAddress(), "Received [%s] bytes from channel:[%s]"::formatted); + readingBuffer.flip(); + try { + readPackets(readingBuffer); + } catch (Exception e) { + log.error(e); + } + + if (reading.compareAndSet(true, false)) { + startRead(); + } + } + + /** + * Handles the exception during receiving data from the channel. + * + * @param exception the exception. + * @param readingBuffer the currently reading buffer. + */ + protected void handleFailedReceiving(Throwable exception, ByteBuffer readingBuffer) { + if (exception instanceof AsynchronousCloseException) { + log.info(connection.remoteAddress(), "Connection:[%s] was closed"::formatted); + } else { + log.error(exception); + connection.close(); + } + } + + /** + * Gets how many packets can be read by the one method call {@link #readPackets(ByteBuffer, ByteBuffer)}}. + */ + protected int maxPacketsByRead() { + return maxPacketsByRead; + } + + protected int readHeader(ByteBuffer buffer, int headerSize) { + switch (headerSize) { + case 1: + return buffer.get() & 0xFF; + case 2: + return buffer.getShort() & 0xFFFF; + case 4: + return buffer.getInt(); + default: + throw new IllegalStateException("Wrong packet's header size: " + headerSize); + } + } + + /** + * Creates a packet to read the received data. + * + * @param buffer the buffer with received data. + * @param startPacketPosition the start position of the packet in the buffer. + * @param packetFullLength the length of packet. + * @param packetDataLength length of packet's data. + * @return the readable packet. + */ + @Nullable + protected abstract R createPacketFor( + ByteBuffer buffer, + int startPacketPosition, + int packetFullLength, + int packetDataLength); + + @Override + public void close() { + + bufferAllocator + .putReadBuffer(readBuffer) + .putPendingBuffer(pendingBuffer); + + freeTempBigBuffers(); + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java similarity index 55% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketWriter.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java index 650b927c..2398a7f6 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java @@ -1,7 +1,6 @@ package javasabr.rlib.network.packet.impl; import static javasabr.rlib.network.util.NetworkUtils.EMPTY_BUFFER; -import static javasabr.rlib.network.util.NetworkUtils.getRemoteAddress; import static javasabr.rlib.network.util.NetworkUtils.hexDump; import java.nio.ByteBuffer; @@ -11,108 +10,116 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.PacketWriter; -import javasabr.rlib.network.packet.WritablePacket; -import javasabr.rlib.network.util.NetworkUtils; +import javasabr.rlib.network.packet.NetworkPacketWriter; +import javasabr.rlib.network.packet.WritableNetworkPacket; +import lombok.AccessLevel; +import lombok.CustomLog; +import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** * @author JavaSaBr */ +@CustomLog @RequiredArgsConstructor -public abstract class AbstractPacketWriter> implements - PacketWriter { +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractNetworkPacketWriter> implements + NetworkPacketWriter { - private static final Logger LOGGER = LoggerManager.getLogger(AbstractPacketWriter.class); - private final CompletionHandler writeHandler = new CompletionHandler<>() { + final CompletionHandler writeHandler = new CompletionHandler<>() { @Override - public void completed(Integer result, WritablePacket packet) { + public void completed(Integer result, WritableNetworkPacket packet) { handleSuccessfulWriting(result, packet); } @Override - public void failed(Throwable exc, WritablePacket packet) { + public void failed(Throwable exc, WritableNetworkPacket packet) { handleFailedWriting(exc, packet); } }; - protected final AtomicBoolean isWriting = new AtomicBoolean(); + final AtomicBoolean writing = new AtomicBoolean(); - protected final C connection; - protected final AsynchronousSocketChannel channel; - protected final BufferAllocator bufferAllocator; - protected final ByteBuffer firstWriteBuffer; - protected final ByteBuffer secondWriteBuffer; + final C connection; + final AsynchronousSocketChannel socketChannel; + final BufferAllocator bufferAllocator; + final ByteBuffer firstWriteBuffer; + final ByteBuffer secondWriteBuffer; - protected volatile @Nullable ByteBuffer firstWriteTempBuffer; - protected volatile @Nullable ByteBuffer secondWriteTempBuffer; + @Nullable + volatile ByteBuffer firstWriteTempBuffer; + @Nullable + volatile ByteBuffer secondWriteTempBuffer; - protected volatile ByteBuffer writingBuffer = EMPTY_BUFFER; + @Getter(AccessLevel.PROTECTED) + volatile ByteBuffer writingBuffer = EMPTY_BUFFER; - protected final Runnable updateActivityFunction; - protected final Supplier<@Nullable WritablePacket> nextWritePacketSupplier; - protected final Consumer writtenPacketHandler; - protected final BiConsumer sentPacketHandler; + final Runnable updateActivityFunction; + final Supplier<@Nullable WritableNetworkPacket> nextWritePacketSupplier; + final BiConsumer sentPacketHandler; + final Consumer packetHandler; - public AbstractPacketWriter( + public AbstractNetworkPacketWriter( C connection, - AsynchronousSocketChannel channel, + AsynchronousSocketChannel socketChannel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - Supplier<@Nullable WritablePacket> packetProvider, - Consumer writtenPacketHandler, - BiConsumer sentPacketHandler) { + Supplier<@Nullable WritableNetworkPacket> packetProvider, + Consumer packetHandler, + BiConsumer sentPacketHandler) { this.connection = connection; - this.channel = channel; + this.socketChannel = socketChannel; this.bufferAllocator = bufferAllocator; this.firstWriteBuffer = bufferAllocator.takeWriteBuffer(); this.secondWriteBuffer = bufferAllocator.takeWriteBuffer(); this.updateActivityFunction = updateActivityFunction; this.nextWritePacketSupplier = packetProvider; - this.writtenPacketHandler = writtenPacketHandler; + this.packetHandler = packetHandler; this.sentPacketHandler = sentPacketHandler; } @Override public void writeNextPacket() { - if (connection.isClosed() || !isWriting.compareAndSet(false, true)) { + if (connection.closed() || !writing.compareAndSet(false, true)) { return; } - var waitPacket = nextWritePacketSupplier.get(); - + WritableNetworkPacket waitPacket = nextWritePacketSupplier.get(); if (waitPacket == null) { - isWriting.set(false); + writing.set(false); return; } - var resultBuffer = serialize(waitPacket); + ByteBuffer resultBuffer = serialize(waitPacket); if (resultBuffer.limit() != 0) { writingBuffer = resultBuffer; - - LOGGER.debug( - channel, - resultBuffer, - (ch, buf) -> "Write to channel \"" + getRemoteAddress(ch) + "\" data:\n" + hexDump(buf)); - - channel.write(resultBuffer, waitPacket, writeHandler); + log.debug(connection.remoteAddress(), resultBuffer, + (address, buf) -> "Write to channel:[%] data:\n" + hexDump(buf)); + socketChannel.write(resultBuffer, waitPacket, writeHandler); } else { - isWriting.set(false); + writing.set(false); } - writtenPacketHandler.accept(waitPacket); + packetHandler.accept(waitPacket); } - protected ByteBuffer serialize(WritablePacket packet) { + /** + * Serializes the network packet to buffer. + * + * @param packet the network packet. + * @return the final byte buffer with data. + */ + protected ByteBuffer serialize(WritableNetworkPacket packet) { if (packet instanceof WritablePacketWrapper) { packet = ((WritablePacketWrapper) packet).getPacket(); @@ -120,13 +127,13 @@ protected ByteBuffer serialize(WritablePacket packet) { W resultPacket = (W) packet; - var expectedLength = packet.getExpectedLength(); - var totalSize = expectedLength == -1 ? -1 : getTotalSize(packet, expectedLength); + int expectedLength = packet.expectedLength(); + int totalSize = expectedLength == -1 ? -1 : totalSize(packet, expectedLength); // if the packet is too big to use a write buffer if (expectedLength != -1 && totalSize > firstWriteBuffer.capacity()) { - var first = bufferAllocator.takeBuffer(totalSize); - var second = bufferAllocator.takeBuffer(totalSize); + ByteBuffer first = bufferAllocator.takeBuffer(totalSize); + ByteBuffer second = bufferAllocator.takeBuffer(totalSize); firstWriteTempBuffer = first; secondWriteTempBuffer = second; return serialize(resultPacket, expectedLength, totalSize, first, second); @@ -136,23 +143,21 @@ protected ByteBuffer serialize(WritablePacket packet) { } /** - * Get a total size of packet if it possible. + * Gets total size of the packet if it's possible. * - * @param packet the packet. - * @param expectedLength the expected size. * @return the total size or -1. */ - protected abstract int getTotalSize(WritablePacket packet, int expectedLength); + protected abstract int totalSize(WritableNetworkPacket packet, int expectedLength); /** - * Serialize packet to byte buffer. + * Serializes the packet to the buffers. * - * @param packet the packet to serialize. + * @param packet the network packet to serialize. * @param expectedLength the packet's expected size. * @param totalSize the packet's total size. - * @param firstBuffer the first byte buffer. - * @param secondBuffer the second byte buffer. - * @return the buffer to write to channel. + * @param firstBuffer the first buffer. + * @param secondBuffer the second buffer. + * @return the final buffer to write to channel. */ protected ByteBuffer serialize( W packet, @@ -162,30 +167,24 @@ protected ByteBuffer serialize( ByteBuffer secondBuffer) { if (!onBeforeWrite(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { - return firstBuffer - .clear() - .limit(0); - } else if (!onWrite(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { - return firstBuffer - .clear() - .limit(0); + return firstBuffer.clear().limit(0); + } else if (!write(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { + return firstBuffer.clear().limit(0); } else if (!onAfterWrite(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { - return firstBuffer - .clear() - .limit(0); + return firstBuffer.clear().limit(0); } return onResult(packet, expectedLength, totalSize, firstBuffer, secondBuffer); } /** - * Handle a byte buffer before writing packet's data. + * Handles the buffers before writing packet's data. * - * @param packet the packet. + * @param packet the network packet. * @param expectedLength the packet's expected size. * @param totalSize the packet's total size. - * @param firstBuffer the first byte buffer. - * @param secondBuffer the second byte buffer. + * @param firstBuffer the first buffer. + * @param secondBuffer the second buffer. * @return true if handling was successful. */ protected boolean onBeforeWrite( @@ -199,16 +198,16 @@ protected boolean onBeforeWrite( } /** - * Write a packet to byte buffer. + * Writes the network packet data to the buffers. * - * @param packet the packet. + * @param packet the network packet. * @param expectedLength the packet's expected size. * @param totalSize the packet's total size. - * @param firstBuffer the first byte buffer. - * @param secondBuffer the second byte buffer. + * @param firstBuffer the first buffer. + * @param secondBuffer the second buffer. * @return true if writing was successful. */ - protected boolean onWrite( + protected boolean write( W packet, int expectedLength, int totalSize, @@ -218,13 +217,13 @@ protected boolean onWrite( } /** - * Handle a byte buffer after writing packet's data. + * Handles the buffers after writing packet's data. * - * @param packet the packet. + * @param packet the network packet. * @param expectedLength the packet's expected size. * @param totalSize the packet's total size. - * @param firstBuffer the first byte buffer. - * @param secondBuffer the second byte buffer. + * @param firstBuffer the first buffer. + * @param secondBuffer the second buffer. * @return true if handling was successful. */ protected boolean onAfterWrite( @@ -238,14 +237,14 @@ protected boolean onAfterWrite( } /** - * Handle a final result byte buffer. + * Handles the final result of writing packet data and return the buffer which contains the data to send. * - * @param packet the packet. + * @param packet the network packet. * @param expectedLength the packet's expected size. * @param totalSize the packet's total size. - * @param firstBuffer the first byte buffer. - * @param secondBuffer the second byte buffer. - * @return the same byte buffer. + * @param firstBuffer the first buffer. + * @param secondBuffer the second buffer. + * @return the result buffer. */ protected ByteBuffer onResult( W packet, @@ -258,7 +257,6 @@ protected ByteBuffer onResult( protected ByteBuffer writeHeader(ByteBuffer buffer, int position, int value, int headerSize) { try { - switch (headerSize) { case 1: buffer.put(position, (byte) value); @@ -272,18 +270,15 @@ protected ByteBuffer writeHeader(ByteBuffer buffer, int position, int value, int default: throw new IllegalStateException("Wrong packet's header size: " + headerSize); } - return buffer; - } catch (IndexOutOfBoundsException ex) { - LOGGER.error( - "Cannot write header by position " + position + " with header size " + headerSize + " to buffer " + buffer); + log.error(position, headerSize, buffer, + "Cannot write header by position:[%s] with header size:[%s] to buffer:[%s]"::formatted); throw ex; } } protected ByteBuffer writeHeader(ByteBuffer buffer, int value, int headerSize) { - switch (headerSize) { case 1: buffer.put((byte) value); @@ -297,63 +292,55 @@ protected ByteBuffer writeHeader(ByteBuffer buffer, int value, int headerSize) { default: throw new IllegalStateException("Wrong packet's header size: " + headerSize); } - return buffer; } /** - * Handle successful wrote data. + * Handles successful wrote data. * - * @param result the count of wrote bytes. + * @param wroteBytes the count of wrote bytes. * @param packet the sent packet. */ - protected void handleSuccessfulWriting(Integer result, WritablePacket packet) { + protected void handleSuccessfulWriting(Integer wroteBytes, WritableNetworkPacket packet) { updateActivityFunction.run(); - if (result == -1) { + if (wroteBytes == -1) { sentPacketHandler.accept(packet, Boolean.FALSE); connection.close(); return; } - var writingBuffer = this.writingBuffer; - + ByteBuffer writingBuffer = writingBuffer(); if (writingBuffer.remaining() > 0) { - LOGGER.debug( - writingBuffer, - channel, - (buf, ch) -> "Buffer was not consumed fully, " + "try to write else " + buf.remaining() + " bytes to channel " - + NetworkUtils.getRemoteAddress(ch)); - channel.write(writingBuffer, packet, writeHandler); + log.debug(writingBuffer, connection.remoteAddress(), + "Buffer was not consumed fully, try to write else [%s] bytes to channel:[%s]"::formatted); + socketChannel.write(writingBuffer, packet, writeHandler); return; } else { - LOGGER.debug(result, bytes -> "Done writing " + bytes + " bytes"); + log.debug(wroteBytes, "Finished writing [%s] bytes"::formatted); } sentPacketHandler.accept(packet, Boolean.TRUE); - if (isWriting.compareAndSet(true, false)) { - + if (writing.compareAndSet(true, false)) { // if we have temp buffers, we can remove it after finishing writing a packet - if (firstWriteTempBuffer != null) { + if (firstWriteTempBuffer != null || secondWriteTempBuffer != null) { clearTempBuffers(); } - writeNextPacket(); } } /** - * Handle the exception during writing the packet. + * Handles the exception during writing the packet. * * @param exception the exception. * @param packet the packet. */ - protected void handleFailedWriting(Throwable exception, WritablePacket packet) { - LOGGER.error(new RuntimeException("Failed writing packet: " + packet, exception)); - - if (!connection.isClosed()) { - if (isWriting.compareAndSet(true, false)) { + protected void handleFailedWriting(Throwable exception, WritableNetworkPacket packet) { + log.error(new RuntimeException("Failed writing packet: " + packet, exception)); + if (!connection.closed()) { + if (writing.compareAndSet(true, false)) { writeNextPacket(); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacket.java deleted file mode 100644 index 739fbb09..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacket.java +++ /dev/null @@ -1,46 +0,0 @@ -package javasabr.rlib.network.packet.impl; - -import static javasabr.rlib.network.util.NetworkUtils.hexDump; - -import java.nio.ByteBuffer; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import javasabr.rlib.network.packet.Packet; - -/** - * The base implementation of {@link Packet}. - * - * @author JavaSaBr - */ -public abstract class AbstractPacket implements Packet { - - protected static final Logger LOGGER = LoggerManager.getLogger(Packet.class); - - /** - * Handle the exception. - * - * @param buffer the data buffer. - * @param exception the exception. - */ - protected void handleException(ByteBuffer buffer, Exception exception) { - LOGGER.warning(exception); - - if (buffer.isDirect()) { - var array = new byte[buffer.limit()]; - buffer.get(array, 0, buffer.limit()); - LOGGER.warning(getName() + " -> buffer: " + buffer + "\n" + hexDump(array, array.length)); - } else { - LOGGER.warning(getName() + " -> buffer: " + buffer + "\n" + hexDump(buffer.array(), buffer.limit())); - } - } - - @Override - public String getName() { - return getClass().getSimpleName(); - } - - @Override - public String toString() { - return getClass().getSimpleName() + "{" + "name='" + getName() + '\'' + '}'; - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketReader.java deleted file mode 100644 index 502545b8..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractPacketReader.java +++ /dev/null @@ -1,478 +0,0 @@ -package javasabr.rlib.network.packet.impl; - -import static javasabr.rlib.common.util.ObjectUtils.notNull; -import static javasabr.rlib.network.util.NetworkUtils.getRemoteAddress; - -import java.nio.ByteBuffer; -import java.nio.channels.AsynchronousCloseException; -import java.nio.channels.AsynchronousSocketChannel; -import java.nio.channels.CompletionHandler; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; -import javasabr.rlib.common.util.BufferUtils; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import javasabr.rlib.network.BufferAllocator; -import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.PacketReader; -import javasabr.rlib.network.packet.ReadablePacket; -import javasabr.rlib.network.util.NetworkUtils; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; -import org.jspecify.annotations.Nullable; - -/** - * @param the readable packet's type. - * @param the connection's type. - * @author JavaSaBr - */ -public abstract class AbstractPacketReader> implements - PacketReader { - - private static final Logger LOGGER = LoggerManager.getLogger(AbstractPacketReader.class); - - private final CompletionHandler readHandler = new CompletionHandler<>() { - - @Override - public void completed(Integer receivedBytes, ByteBuffer readingBuffer) { - handleReceivedData(receivedBytes, readingBuffer); - } - - @Override - public void failed(Throwable exc, ByteBuffer readingBuffer) { - handleFailedReceiving(exc, readingBuffer); - } - }; - - protected final AtomicBoolean isReading = new AtomicBoolean(false); - - protected final C connection; - protected final AsynchronousSocketChannel channel; - protected final BufferAllocator bufferAllocator; - - protected final ByteBuffer readBuffer; - protected final ByteBuffer pendingBuffer; - - protected final Runnable updateActivityFunction; - protected final Consumer readPacketHandler; - - @Getter(AccessLevel.PROTECTED) - @Setter(AccessLevel.PROTECTED) - protected volatile @Nullable ByteBuffer tempPendingBuffer; - - protected final int maxPacketsByRead; - - protected AbstractPacketReader( - C connection, - AsynchronousSocketChannel channel, - BufferAllocator bufferAllocator, - Runnable updateActivityFunction, - Consumer readPacketHandler, - int maxPacketsByRead) { - this.connection = connection; - this.channel = channel; - this.bufferAllocator = bufferAllocator; - this.readBuffer = bufferAllocator.takeReadBuffer(); - this.pendingBuffer = bufferAllocator.takePendingBuffer(); - this.updateActivityFunction = updateActivityFunction; - this.readPacketHandler = readPacketHandler; - this.maxPacketsByRead = maxPacketsByRead; - } - - protected ByteBuffer getBufferToReadFromChannel() { - return readBuffer; - } - - @Override - public void startRead() { - - if (!isReading.compareAndSet(false, true)) { - return; - } - - LOGGER.debug(channel, ch -> "Start waiting for new data from channel \"" + getRemoteAddress(ch) + "\""); - - var buffer = getBufferToReadFromChannel(); - - channel.read(buffer, buffer, readHandler); - } - - /** - * Read packets from the buffer with received data. - * - * @param receivedBuffer the buffer with received data. - * @return count of read packets. - */ - protected int readPackets(ByteBuffer receivedBuffer) { - return readPackets(receivedBuffer, pendingBuffer); - } - - /** - * Read packets from the buffer with received data. - * - * @param receivedBuffer the buffer with received data. - * @param pendingBuffer the buffer with pending data from prev. received buffer. - * @return count of read packets. - */ - protected int readPackets(ByteBuffer receivedBuffer, ByteBuffer pendingBuffer) { - - LOGGER.debug(receivedBuffer, buf -> "Start reading packets from received buffer " + buf); - - var waitedBytes = pendingBuffer.position(); - var bufferToRead = receivedBuffer; - var tempPendingBuffer = getTempPendingBuffer(); - - // if we have a temp buffer it means that we are reading a really big packet now - if (tempPendingBuffer != null) { - - if (tempPendingBuffer.remaining() < receivedBuffer.remaining()) { - reAllocTempBuffers(tempPendingBuffer.flip(), tempPendingBuffer.capacity()); - tempPendingBuffer = notNull(getTempPendingBuffer()); - } - - LOGGER.debug( - receivedBuffer, - tempPendingBuffer, - (buf, mappedBuf) -> "Put received buffer " + buf + " to read mapped buffer " + mappedBuf); - - bufferToRead = BufferUtils.putToAndFlip(tempPendingBuffer, receivedBuffer); - } - // if we have some pending data we need to append the received buffer to the pending buffer - // and start to read pending buffer with result received data - else if (waitedBytes > 0) { - - if (pendingBuffer.remaining() < receivedBuffer.remaining()) { - - LOGGER.debug( - pendingBuffer, - receivedBuffer, - (penBuf, buf) -> "Pending buffer " + penBuf + " is too small to append received buffer " + buf - + ", will allocate new temp buffer for this"); - - allocTempBuffers(pendingBuffer.flip(), pendingBuffer.capacity()); - - LOGGER.debug(pendingBuffer, buf -> "Clear pending buffer: " + buf); - - pendingBuffer.clear(); - - tempPendingBuffer = notNull(getTempPendingBuffer()); - - LOGGER.debug( - receivedBuffer, - tempPendingBuffer, - (buf, mappedBuf) -> "Put received buffer: " + buf + " to mapped buffer: " + mappedBuf); - - bufferToRead = BufferUtils.putToAndFlip(tempPendingBuffer, receivedBuffer); - - } else { - - LOGGER.debug( - receivedBuffer, - pendingBuffer, - (buf, penBuf) -> "Put received buffer: " + buf + " to pending buffer: " + penBuf); - - bufferToRead = BufferUtils.putToAndFlip(pendingBuffer, receivedBuffer); - } - } - - var maxPacketsByRead = getMaxPacketsByRead(); - - var readPackets = 0; - var endPosition = 0; - - while (canStartReadPacket(bufferToRead) && readPackets < maxPacketsByRead) { - - // set position of start a next packet - bufferToRead.position(endPosition); - - var positionBeforeRead = endPosition; - var packetLength = readPacketLength(bufferToRead); - var dataLength = getDataLength(packetLength, bufferToRead.position() - endPosition, bufferToRead); - - LOGGER.debug( - packetLength, - positionBeforeRead, - (length, pos) -> "Find next packet from position: " + pos + " with length: " + length); - - // calculate position of end the next packet - endPosition += packetLength; - - // if the packet isn't full presented in this buffer - if (packetLength == -1 || endPosition > bufferToRead.limit()) { - - bufferToRead.position(positionBeforeRead); - - // if we read the received buffer we need to put - // not read data to the pending buffer or big mapped byte buffer - if (bufferToRead == receivedBuffer) { - if (packetLength <= pendingBuffer.capacity()) { - pendingBuffer.put(receivedBuffer); - LOGGER.debug(pendingBuffer, buf -> "Put pending data form received buffer to pending buffer: " + buf); - } else { - allocTempBuffers(receivedBuffer, packetLength); - } - } - // if we already read this pending buffer we need to compact it - else if (bufferToRead == pendingBuffer) { - - if (packetLength <= pendingBuffer.capacity()) { - pendingBuffer.compact(); - LOGGER.debug(pendingBuffer, buf -> "Compact pending buffer: " + buf); - } else { - allocTempBuffers(pendingBuffer, packetLength); - LOGGER.debug(pendingBuffer, buf -> "Clear pending buffer: " + buf); - pendingBuffer.clear(); - } - - } else if (bufferToRead == tempPendingBuffer) { - - // if not read data is less than pending buffer then we can switch to use the pending buffer - if (Math.max(packetLength, tempPendingBuffer.remaining()) <= pendingBuffer.capacity()) { - - pendingBuffer - .clear() - .put(tempPendingBuffer); - - LOGGER.debug(pendingBuffer, buf -> "Moved pending data from mapped buffer to pending buffer: " + buf); - - freeTempBuffers(); - } - // if a new packet is bigger than current read mapped buffer - else if (packetLength > tempPendingBuffer.capacity()) { - reAllocTempBuffers(tempPendingBuffer, packetLength); - } - // or just compact this current mapped buffer - else { - tempPendingBuffer.compact(); - LOGGER.debug(tempPendingBuffer, buf -> "Compact mapped buffer: " + buf); - } - } - - LOGGER.debug( - channel, - readPackets, - (ch, count) -> "Read " + count + " packets from received buffer of " + getRemoteAddress(ch) + ", " - + "but 1 packet is still waiting for receiving additional data."); - - receivedBuffer.clear(); - return readPackets; - } - - R packet = createPacketFor(bufferToRead, positionBeforeRead, packetLength, dataLength); - - if (packet != null) { - LOGGER.debug(packet, pck -> "Created instance of packet to read data: " + pck); - readAndHandlePacket(bufferToRead, dataLength, packet); - LOGGER.debug(packet, pck -> "Finished reading data of packet: " + pck); - readPackets++; - } else { - LOGGER.warning("Cannot create any instance of packet to read data"); - } - - bufferToRead.position(endPosition); - } - - if (bufferToRead.hasRemaining()) { - - if (bufferToRead == receivedBuffer) { - pendingBuffer.put(receivedBuffer); - LOGGER.debug("Found not yet read data from receive buffer, will put it to pending buffer."); - } else { - bufferToRead.compact(); - } - - } else if (bufferToRead == pendingBuffer) { - pendingBuffer.clear(); - } else if (tempPendingBuffer != null) { - freeTempBuffers(); - } - - LOGGER.debug( - channel, - readPackets, - (ch, count) -> "Read " + count + " packets from received buffer of " + getRemoteAddress(ch) + "."); - - receivedBuffer.clear(); - return readPackets; - } - - protected void readAndHandlePacket(ByteBuffer bufferToRead, int dataLength, R packet) { - if (packet.read(connection, bufferToRead, dataLength)) { - readPacketHandler.accept(packet); - } else { - LOGGER.error("Packet " + packet + " was read incorrectly"); - } - } - - /** - * Check buffer's data. - * - * @param buffer the buffer to read. - * @return true if this buffer has enough data to start initial reading. - */ - protected abstract boolean canStartReadPacket(ByteBuffer buffer); - - /** - * Calculate size of packet data. - * - * @param packetLength the full packet length. - * @param readBytes the count of already read bytes from buffer to get packet length. - * @param buffer the buffer. - * @return the length of packet data part. - */ - protected int getDataLength(int packetLength, int readBytes, ByteBuffer buffer) { - return packetLength - readBytes; - } - - /** - * Get the packet's data length of next packet in the buffer. - * - * @param buffer the buffer with received data. - * @return the packet length or -1 if we have no enough data to read length. - */ - protected abstract int readPacketLength(ByteBuffer buffer); - - protected void reAllocTempBuffers(ByteBuffer sourceBuffer, int packetLength) { - - LOGGER.debug( - sourceBuffer.capacity(), - packetLength, - (currentSize, newSize) -> "Resize read temp buffer from " + currentSize + " to " + newSize); - - var newReadTempBuffer = bufferAllocator.takeBuffer(packetLength + readBuffer.capacity()); - - LOGGER.debug( - sourceBuffer, - newReadTempBuffer, - (old, buf) -> "Moved pending data from old temp buffer " + old + " to new temp buffer " + buf); - - newReadTempBuffer.put(sourceBuffer); - - freeTempBuffers(); - - this.tempPendingBuffer = newReadTempBuffer; - } - - protected void allocTempBuffers(ByteBuffer sourceBuffer, int packetLength) { - - LOGGER.debug( - packetLength, - sourceBuffer.remaining(), - (length, part) -> "Request temp buffer to store a part: " + part + " of big packet with length: " + length); - - var readTempBuffer = bufferAllocator.takeBuffer(packetLength + readBuffer.capacity()); - - LOGGER.debug( - sourceBuffer, - readTempBuffer, - (recBuf, buf) -> "Put the part of packet: " + recBuf + " to mapped buffer: " + buf); - - readTempBuffer.put(sourceBuffer); - - this.tempPendingBuffer = readTempBuffer; - } - - protected void freeTempBuffers() { - - var readTempBuffer = getTempPendingBuffer(); - - if (readTempBuffer != null) { - setTempPendingBuffer(null); - bufferAllocator.putBuffer(readTempBuffer); - } - } - - /** - * Handle received data. - * - * @param receivedBytes the count of received bytes. - * @param readingBuffer the currently reading buffer. - */ - protected void handleReceivedData(Integer receivedBytes, ByteBuffer readingBuffer) { - updateActivityFunction.run(); - - if (receivedBytes == -1) { - connection.close(); - return; - } - - LOGGER.debug( - receivedBytes, - channel, - (bytes, ch) -> "Received " + bytes + " bytes from channel \"" + NetworkUtils.getRemoteAddress(ch) + "\""); - - readingBuffer.flip(); - try { - readPackets(readingBuffer); - } catch (Exception e) { - LOGGER.error(e); - } - - if (isReading.compareAndSet(true, false)) { - startRead(); - } - } - - /** - * Handle the exception during receiving data. - * - * @param exception the exception. - * @param readingBuffer the currently reading buffer. - */ - protected void handleFailedReceiving(Throwable exception, ByteBuffer readingBuffer) { - if (exception instanceof AsynchronousCloseException) { - LOGGER.info(connection, cn -> "Connection " + cn.getRemoteAddress() + " was closed."); - } else { - LOGGER.error(exception); - connection.close(); - } - } - - /** - * Get the how many packets can be read by the one method call {@link #readPackets(ByteBuffer, ByteBuffer)}}. - * - * @return the how many packets can be read. - */ - protected int getMaxPacketsByRead() { - return maxPacketsByRead; - } - - protected int readHeader(ByteBuffer buffer, int headerSize) { - switch (headerSize) { - case 1: - return buffer.get() & 0xFF; - case 2: - return buffer.getShort() & 0xFFFF; - case 4: - return buffer.getInt(); - default: - throw new IllegalStateException("Wrong packet's header size: " + headerSize); - } - } - - /** - * Create a packet to read received data. - * - * @param buffer the buffer with received data. - * @param startPacketPosition the start position of the packet in the buffer. - * @param packetLength the length of packet. - * @param dataLength length of packet's data. - * @return the readable packet. - */ - protected abstract @Nullable R createPacketFor( - ByteBuffer buffer, - int startPacketPosition, - int packetLength, - int dataLength); - - @Override - public void close() { - - bufferAllocator - .putReadBuffer(readBuffer) - .putPendingBuffer(pendingBuffer); - - freeTempBuffers(); - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java new file mode 100644 index 00000000..ca47c5a4 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java @@ -0,0 +1,126 @@ +package javasabr.rlib.network.packet.impl; + +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import javasabr.rlib.common.util.ClassUtils; +import javasabr.rlib.network.Connection; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import lombok.AccessLevel; +import lombok.CustomLog; +import lombok.NoArgsConstructor; + +/** + * The base implementation of {@link ReadableNetworkPacket}. + * + * @author JavaSaBr + */ +@CustomLog +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public abstract class AbstractReadableNetworkPacket + extends AbstractNetworkPacket implements ReadableNetworkPacket { + + @Override + public boolean read(ByteBuffer buffer, int expectedLength) { + int oldLimit = buffer.limit(); + try { + buffer.limit(buffer.position() + expectedLength); + readImpl(buffer); + return true; + } catch (Exception e) { + handleException(buffer, e); + return false; + } finally { + buffer.limit(oldLimit); + } + } + + protected void readImpl(ByteBuffer buffer) {} + + /** + * Reads 1 byte from the buffer. + */ + protected int readByte(ByteBuffer buffer) { + return buffer.get(); + } + + /** + * Fills byte array with data from the buffer. + */ + protected void readBytes(ByteBuffer buffer, byte[] array) { + buffer.get(array); + } + + /** + * Fills byte array with data from the buffer. + */ + protected void readBytes(ByteBuffer buffer, byte[] array, int offset, int length) { + buffer.get(array, offset, length); + } + + /** + * Reads 4 bytes from buffer. + */ + protected float readFloat(ByteBuffer buffer) { + return buffer.getFloat(); + } + + /** + * Reads 8 bytes from buffer. + */ + protected double readDouble(ByteBuffer buffer) { + return buffer.getDouble(); + } + + /** + * Reads 4 bytes from buffer. + */ + protected int readInt(ByteBuffer buffer) { + return buffer.getInt(); + } + + /** + * Reads 8 bytes from buffer. + */ + protected long readLong(ByteBuffer buffer) { + return buffer.getLong(); + } + + /** + * Reads 2 bytes from buffer. + */ + protected int readShort(ByteBuffer buffer) { + return buffer.getShort(); + } + + /** + * Read a string from buffer. + */ + protected String readString(ByteBuffer buffer, int maxLength) { + int length = readInt(buffer); + if (maxLength < length) { + throw new IllegalArgumentException("Buffer contains too long string:[%s] with limit:[%s]".formatted( + length, + maxLength)); + } + try { + int requiredRemainingBytes = length * 2; + if (requiredRemainingBytes > buffer.remaining()) { + throw new IllegalArgumentException("Buffer:[%s] has no enough data for string:[%s]".formatted(buffer, length)); + } + + var chars = new char[length]; + + for (int i = 0; i < length; i++) { + chars[i] = buffer.getChar(); + } + + return new String(chars); + } catch (OutOfMemoryError ex) { + log.error(length, "Cannot read too long string:[%s] by memory reason"::formatted); + throw ex; + } catch (BufferUnderflowException ex) { + log.error(length, buffer, "Cannot read too long string:[%s] by not enough data in buffer:[%s]"::formatted); + throw ex; + } + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadablePacket.java deleted file mode 100644 index 86a24316..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadablePacket.java +++ /dev/null @@ -1,161 +0,0 @@ -package javasabr.rlib.network.packet.impl; - -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.ReadablePacket; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -/** - * The base implementation of {@link ReadablePacket}. - * - * @author JavaSaBr - */ -@NoArgsConstructor(access = AccessLevel.PROTECTED) -public abstract class AbstractReadablePacket> extends AbstractPacket implements - ReadablePacket { - - @Override - public boolean read(Connection connection, ByteBuffer buffer, int length) { - var oldLimit = buffer.limit(); - try { - buffer.limit(buffer.position() + length); - readImpl(ClassUtils.unsafeNNCast(connection), buffer); - return true; - } catch (Exception e) { - handleException(buffer, e); - return false; - } finally { - buffer.limit(oldLimit); - } - } - - /** - * Read packet's data from byte buffer. - * - * @param connection the network connection. - * @param buffer the buffer with received data. - */ - protected void readImpl(C connection, ByteBuffer buffer) { - } - - /** - * Read 1 byte from buffer. - * - * @param buffer the buffer to read. - * @return 1 byte from the buffer. - */ - protected int readByte(ByteBuffer buffer) { - return buffer.get(); - } - - /** - * Fill byte array with data from received buffer. - * - * @param buffer the buffer to read. - * @param array the filled byte array. - */ - protected void readBytes(ByteBuffer buffer, byte[] array) { - buffer.get(array); - } - - /** - * Fill byte array with data from received buffer. - * - * @param buffer the buffer to read. - * @param array the byte array. - * @param offset the offset to fill the byte array. - * @param length the length to fill the byte array. - */ - protected void readBytes(ByteBuffer buffer, byte[] array, int offset, int length) { - buffer.get(array, offset, length); - } - - /** - * Read 4 bytes from buffer. - * - * @param buffer the buffer to read. - * @return 4 bytes as float from the buffer. - */ - protected float readFloat(ByteBuffer buffer) { - return buffer.getFloat(); - } - - /** - * Read 8 bytes from buffer. - * - * @param buffer the buffer to read. - * @return 4 bytes as double from the buffer. - */ - protected double readDouble(ByteBuffer buffer) { - return buffer.getDouble(); - } - - /** - * Read 4 bytes from buffer. - * - * @param buffer the buffer to read. - * @return 4 bytes as int from the buffer. - */ - protected int readInt(ByteBuffer buffer) { - return buffer.getInt(); - } - - /** - * Read 8 bytes from buffer. - * - * @param buffer the buffer to read. - * @return 8 bytes as long from buffer. - */ - protected long readLong(ByteBuffer buffer) { - return buffer.getLong(); - } - - /** - * Read 2 bytes from buffer. - * - * @param buffer the buffer to read. - * @return 2 bytes as short from buffer. - */ - protected int readShort(ByteBuffer buffer) { - return buffer.getShort(); - } - - /** - * Read a string from buffer. - * - * @param buffer the buffer to read. - * @return the read string from the buffer. - */ - protected String readString(ByteBuffer buffer) { - - var length = readInt(buffer); - try { - - var requiredRemainingBytes = length * 2; - - if (requiredRemainingBytes > buffer.remaining()) { - throw new IllegalStateException("Found too long string " + length + " from buffer " + buffer); - } - - var array = new char[length]; - - for (int i = 0; i < length; i++) { - array[i] = buffer.getChar(); - } - - return new String(array); - - } catch (OutOfMemoryError ex) { - LOGGER.error("Cannot read too long \"" + length + "\" string by memory reason"); - throw ex; - } catch (BufferUnderflowException ex) { - LOGGER.error( - "Cannot read string because buffer doesn't contains enough data. " + "Expected string length " + length - + ", buffer " + buffer); - throw ex; - } - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReusableWritablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReusableWritableNetworkPacket.java similarity index 76% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReusableWritablePacket.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReusableWritableNetworkPacket.java index 6f004c3d..30c057a2 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReusableWritablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReusableWritableNetworkPacket.java @@ -10,30 +10,37 @@ import javasabr.rlib.network.packet.ReusableWritablePacket; import javasabr.rlib.reusable.pool.Pool; import javasabr.rlib.reusable.pool.PoolFactory; +import lombok.AccessLevel; +import lombok.CustomLog; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * The reusable implementation of {@link AbstractWritablePacket} using the counter to control the life cycle of this + * The reusable implementation of {@link AbstractWritableNetworkPacket} using the counter to control the life cycle of this * packet. * * @author JavaSaBr */ -public abstract class AbstractReusableWritablePacket extends AbstractWritablePacket implements ReusableWritablePacket { +@CustomLog +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractReusableWritableNetworkPacket extends AbstractWritableNetworkPacket + implements ReusableWritablePacket { - protected static final ThreadLocal, Pool>> LOCAL_POOLS = ThreadLocal.withInitial( - HashMap::new); + protected static final ThreadLocal, Pool>> + LOCAL_POOLS = ThreadLocal.withInitial(HashMap::new); - protected final AtomicInteger counter; + final AtomicInteger counter; /** * The pool to store this packet after using. */ - protected volatile @Nullable Pool pool; - protected volatile int barrier; + @Nullable + volatile Pool pool; + volatile int barrier; - protected int barrierSink; + int barrierSink; - public AbstractReusableWritablePacket() { + public AbstractReusableWritableNetworkPacket() { this.counter = new AtomicInteger(); } @@ -41,11 +48,8 @@ public AbstractReusableWritablePacket() { public boolean write(ByteBuffer buffer) { if (counter.get() < 1) { - LOGGER.warning( - this, - arg -> "Attempt to write is already finished packet " + arg + " on thread " + Thread - .currentThread() - .getName()); + log.warning(this, arg -> + "Attempt to write is already finished packet:[%s] on thread:[%s]".formatted(arg, Thread.currentThread().getName())); return false; } @@ -115,11 +119,11 @@ public void forceComplete() { } /** - * Get thread local pool. + * Gets thread local pool. * * @return thread local pool. */ - protected Pool getThreadLocalPool() { + protected Pool threadLocalPool() { Class packetClass = ClassUtils.unsafeNNCast(getClass()); return LOCAL_POOLS .get() @@ -127,22 +131,20 @@ protected Pool getThreadLocalPool() { } /** - * Get the pool to store used packet. + * Gets the pool to store used packet. * * @return the pool to store used packet. */ protected Pool getPool() { Pool local = this.pool; - if (local != null) { return local; } - this.pool = getThreadLocalPool(); + this.pool = threadLocalPool(); local = this.pool; - return notNull(local); } @@ -200,6 +202,6 @@ public void increaseSends(int count) { @Override public String toString() { - return "AbstractReusableSendablePacket{" + "counter=" + counter + "} " + super.toString(); + return "AbstractReusableWritableNetworkPacket{" + "counter=" + counter + "} " + super.toString(); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSSLPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java similarity index 73% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSSLPacketReader.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java index 3ec1d274..fc145b98 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSSLPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java @@ -5,27 +5,28 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; -import javasabr.rlib.common.function.NotNullConsumer; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; +import java.util.function.Consumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.ReadablePacket; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; import javasabr.rlib.network.util.NetworkUtils; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLException; +import lombok.AccessLevel; +import lombok.CustomLog; +import lombok.experimental.FieldDefaults; /** * @param the readable packet's type. * @param the connection's type. */ -public abstract class AbstractSSLPacketReader> extends - AbstractPacketReader { - - private static final Logger LOGGER = LoggerManager.getLogger(AbstractSSLPacketReader.class); +@CustomLog +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractSslNetworkPacketReader> + extends AbstractNetworkPacketReader { private static final ByteBuffer[] EMPTY_BUFFERS = { NetworkUtils.EMPTY_BUFFER @@ -33,20 +34,20 @@ public abstract class AbstractSSLPacketReader packetWriter; + final SSLEngine sslEngine; + final Consumer packetWriter; - protected volatile ByteBuffer sslNetworkBuffer; - protected volatile ByteBuffer sslDataBuffer; + volatile ByteBuffer sslNetworkBuffer; + volatile ByteBuffer sslDataBuffer; - protected AbstractSSLPacketReader( + protected AbstractSslNetworkPacketReader( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NotNullConsumer readPacketHandler, + Consumer readPacketHandler, SSLEngine sslEngine, - NotNullConsumer packetWriter, + Consumer packetWriter, int maxPacketsByRead) { super(connection, channel, bufferAllocator, updateActivityFunction, readPacketHandler, maxPacketsByRead); this.sslEngine = sslEngine; @@ -60,26 +61,22 @@ protected AbstractSSLPacketReader( } @Override - protected ByteBuffer getBufferToReadFromChannel() { + protected ByteBuffer bufferToReadFromChannel() { return sslNetworkBuffer; } @Override protected void handleReceivedData(Integer receivedBytes, ByteBuffer readingBuffer) { - if (receivedBytes == -1) { doHandshake(readingBuffer, -1); return; } - super.handleReceivedData(receivedBytes, readingBuffer); } @Override protected int readPackets(ByteBuffer receivedBuffer) { - var handshakeStatus = sslEngine.getHandshakeStatus(); - // ssl engine is ready to decrypt if (handshakeStatus == HandshakeStatus.FINISHED || handshakeStatus == HandshakeStatus.NOT_HANDSHAKING) { return decryptAndRead(receivedBuffer); @@ -89,19 +86,15 @@ protected int readPackets(ByteBuffer receivedBuffer) { } protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { - - var handshakeStatus = sslEngine.getHandshakeStatus(); - + HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); while (handshakeStatus != HandshakeStatus.FINISHED && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) { - LOGGER.debug(handshakeStatus, status -> "Do handshake with status: " + status); + log.debug(handshakeStatus, "Do handshake with status:[%s] "::formatted); SSLEngineResult result; switch (handshakeStatus) { case NEED_UNWRAP: { - if (receivedBytes == -1) { - if (sslEngine.isInboundDone() && sslEngine.isOutboundDone()) { return SKIP_READ_PACKETS; } @@ -109,7 +102,7 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { try { sslEngine.closeInbound(); } catch (SSLException e) { - LOGGER.error("This engine was forced to close inbound, without having received the " + log.error("This engine was forced to close inbound, without having received the " + "proper SSL/TLS close notification message from the peer, due to end of stream."); } @@ -123,12 +116,12 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { } try { - LOGGER.debug(receivedBuffer, buff -> "Try to unwrap data:\n" + hexDump(buff)); + log.debug(receivedBuffer, buff -> "Try to unwrap data:\n" + hexDump(buff)); result = sslEngine.unwrap(receivedBuffer, EMPTY_BUFFERS); handshakeStatus = result.getHandshakeStatus(); - LOGGER.debug(handshakeStatus, status -> "Handshake status: " + status + " after unwrapping"); + log.debug(handshakeStatus, "Handshake status:[%s] after unwrapping"::formatted); } catch (SSLException sslException) { - LOGGER.error("A problem was encountered while processing the data that caused the " + log.error("A problem was encountered while processing the data that caused the " + "SSLEngine to abort. Will try to properly close connection..."); sslEngine.closeOutbound(); handshakeStatus = sslEngine.getHandshakeStatus(); @@ -141,7 +134,7 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { case BUFFER_OVERFLOW: throw new IllegalStateException("Unexpected ssl engine result"); case BUFFER_UNDERFLOW: - LOGGER.debug("Increase ssl network buffer"); + log.debug("Increase ssl network buffer"); increaseNetworkBuffer(); break; case CLOSED: @@ -157,23 +150,23 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { } break; } - case NEED_WRAP: - LOGGER.debug("Send command to wrap data"); - packetWriter.accept(SSLWritablePacket.getInstance()); + case NEED_WRAP: { + log.debug("Send command to wrap data"); + packetWriter.accept(SslWritableNetworkPacket.getInstance()); sslNetworkBuffer.clear(); return SKIP_READ_PACKETS; - case NEED_TASK: + } + case NEED_TASK: { Runnable task; while ((task = sslEngine.getDelegatedTask()) != null) { - LOGGER.debug(task, t -> "Execute SSL Engine's task: " + t.getClass()); + log.debug(task, "Execute SSL Engine's task:[%s]"::formatted); task.run(); } handshakeStatus = sslEngine.getHandshakeStatus(); - - LOGGER.debug(handshakeStatus, status -> "Handshake status: " + status + " after engine tasks"); + log.debug(handshakeStatus, "Handshake status:[%s] after engine tasks"::formatted); if (handshakeStatus == HandshakeStatus.NEED_UNWRAP && !receivedBuffer.hasRemaining()) { sslNetworkBuffer.clear(); @@ -181,8 +174,10 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { } break; - default: + } + default: { throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); + } } } @@ -190,7 +185,7 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { // if buffer is empty and status is FINISHED then we can notify writer if (handshakeStatus == HandshakeStatus.FINISHED) { - packetWriter.accept(SSLWritablePacket.getInstance()); + packetWriter.accept(SslWritableNetworkPacket.getInstance()); } receivedBuffer.clear(); @@ -206,41 +201,40 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { int total = 0; while (receivedBuffer.hasRemaining()) { - SSLEngineResult result; try { - LOGGER.debug(receivedBuffer, buf -> "Try to decrypt data:\n" + hexDump(buf)); + log.debug(receivedBuffer, buf -> "Try to decrypt data:\n" + hexDump(buf)); result = sslEngine.unwrap(receivedBuffer, sslDataBuffer.clear()); } catch (SSLException e) { - var handshakeStatus = sslEngine.getHandshakeStatus(); throw new IllegalStateException(e); } switch (result.getStatus()) { - case OK: + case OK: { sslDataBuffer.flip(); - LOGGER.debug(sslDataBuffer, buf -> "Decrypted data:\n" + hexDump(buf)); + log.debug(sslDataBuffer, buf -> "Decrypted data:\n" + hexDump(buf)); total += readPackets(sslDataBuffer, pendingBuffer); break; - case BUFFER_OVERFLOW: + } + case BUFFER_OVERFLOW: { increaseDataBuffer(); return decryptAndRead(receivedBuffer); - case CLOSED: + } + case CLOSED: { closeConnection(); return SKIP_READ_PACKETS; - default: - + } + default: { if (receivedBuffer.position() > 0) { receivedBuffer.compact(); return total; } - throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } } } receivedBuffer.clear(); - return total; } @@ -255,7 +249,7 @@ private void increaseDataBuffer() { protected void closeConnection() { try { sslEngine.closeOutbound(); - channel.close(); + socketChannel.close(); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSSLPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java similarity index 59% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSSLPacketWriter.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java index 3b96e8be..17815f1a 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSSLPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java @@ -6,47 +6,48 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; -import javasabr.rlib.common.function.NotNullBiConsumer; -import javasabr.rlib.common.function.NotNullConsumer; -import javasabr.rlib.common.function.NullableSupplier; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; import javasabr.rlib.network.util.NetworkUtils; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLException; +import lombok.AccessLevel; +import lombok.CustomLog; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; -public abstract class AbstractSSLPacketWriter> extends - AbstractPacketWriter { - - private static final Logger LOGGER = LoggerManager.getLogger(AbstractSSLPacketWriter.class); +@CustomLog +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractSslNetworkPacketWriter> + extends AbstractNetworkPacketWriter { private static final ByteBuffer[] EMPTY_BUFFERS = { NetworkUtils.EMPTY_BUFFER }; - protected final SSLEngine sslEngine; - protected final NotNullConsumer packetWriter; - protected final NotNullConsumer queueAtFirst; + final SSLEngine sslEngine; + final Consumer packetWriter; + final Consumer queueAtFirst; protected volatile ByteBuffer sslNetworkBuffer; - public AbstractSSLPacketWriter( + public AbstractSslNetworkPacketWriter( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NullableSupplier packetProvider, - NotNullConsumer writtenPacketHandler, - NotNullBiConsumer sentPacketHandler, + Supplier packetProvider, + Consumer writtenPacketHandler, + BiConsumer sentPacketHandler, SSLEngine sslEngine, - NotNullConsumer packetWriter, - NotNullConsumer queueAtFirst) { + Consumer packetWriter, + Consumer queueAtFirst) { super( connection, channel, @@ -65,55 +66,50 @@ public AbstractSSLPacketWriter( @Override public void writeNextPacket() { - - var status = sslEngine.getHandshakeStatus(); - - switch (status) { - case NEED_UNWRAP: - return; + HandshakeStatus status = sslEngine.getHandshakeStatus(); + if (status == HandshakeStatus.NEED_UNWRAP) { + return; } - super.writeNextPacket(); } @Override - protected ByteBuffer serialize(WritablePacket packet) { - - var status = sslEngine.getHandshakeStatus(); - + protected ByteBuffer serialize(WritableNetworkPacket packet) { + HandshakeStatus status = sslEngine.getHandshakeStatus(); if (status == HandshakeStatus.FINISHED || status == HandshakeStatus.NOT_HANDSHAKING) { - - if (packet instanceof SSLWritablePacket) { + if (packet instanceof SslWritableNetworkPacket) { return EMPTY_BUFFER; } - var dataBuffer = super.serialize(packet); - - LOGGER.debug(dataBuffer, buff -> "Try to encrypt data:\n" + hexDump(buff)); + ByteBuffer packetDataBuffer = super.serialize(packet); + log.debug(packetDataBuffer, buff -> "Try to encrypt data:\n" + hexDump(buff)); SSLEngineResult result; try { - result = sslEngine.wrap(dataBuffer, sslNetworkBuffer.clear()); + result = sslEngine.wrap(packetDataBuffer, sslNetworkBuffer.clear()); } catch (SSLException e) { throw new RuntimeException(e); } switch (result.getStatus()) { - case BUFFER_UNDERFLOW: + case BUFFER_UNDERFLOW: { increaseNetworkBuffer(); break; - case BUFFER_OVERFLOW: + } + case BUFFER_OVERFLOW: { throw new IllegalStateException("Unexpected ssl engine result"); - case OK: + } + case OK: { return sslNetworkBuffer.flip(); - case CLOSED: + } + case CLOSED: { closeConnection(); return EMPTY_BUFFER; + } } } - var bufferToWrite = doHandshake(packet); - + ByteBuffer bufferToWrite = doHandshake(packet); if (bufferToWrite != null) { return bufferToWrite; } @@ -121,28 +117,25 @@ protected ByteBuffer serialize(WritablePacket packet) { throw new IllegalStateException(); } - protected @Nullable ByteBuffer doHandshake(WritablePacket packet) { - - if (!(packet instanceof SSLWritablePacket)) { - LOGGER.debug(packet, pck -> "Return packet " + pck + " to queue as first"); + @Nullable + protected ByteBuffer doHandshake(WritableNetworkPacket packet) { + if (!(packet instanceof SslWritableNetworkPacket)) { + log.debug(packet, "Return packet:[%s] to queue as first"::formatted); queueAtFirst.accept(packet); } - var handshakeStatus = sslEngine.getHandshakeStatus(); + HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); while (handshakeStatus != HandshakeStatus.FINISHED && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) { - SSLEngineResult result; - switch (handshakeStatus) { - - case NEED_WRAP: + case NEED_WRAP: { try { // check result result = sslEngine.wrap(EMPTY_BUFFERS, sslNetworkBuffer.clear()); handshakeStatus = result.getHandshakeStatus(); } catch (SSLException sslException) { - LOGGER.error("A problem was encountered while processing the data that caused the SSLEngine " + log.error("A problem was encountered while processing the data that caused the SSLEngine " + "to abort. Will try to properly close connection..."); sslEngine.closeOutbound(); handshakeStatus = sslEngine.getHandshakeStatus(); @@ -150,46 +143,50 @@ protected ByteBuffer serialize(WritablePacket packet) { } switch (result.getStatus()) { case OK: - sslNetworkBuffer.flip(); - if (handshakeStatus == HandshakeStatus.NEED_WRAP) { - LOGGER.debug("Send command to wrap data again"); - queueAtFirst.accept(SSLWritablePacket.getInstance()); + log.debug("Send command to wrap data again"); + queueAtFirst.accept(SslWritableNetworkPacket.getInstance()); } - - LOGGER.debug(sslNetworkBuffer, result, (buf, res) -> "Send wrapped data:\n" + hexDump(buf, res)); - + log.debug(sslNetworkBuffer, result, (buf, res) -> "Send wrapped data:\n" + hexDump(buf, res)); return sslNetworkBuffer; - case BUFFER_OVERFLOW: + case BUFFER_OVERFLOW: { sslNetworkBuffer = NetworkUtils.enlargePacketBuffer(bufferAllocator, sslEngine); break; - case BUFFER_UNDERFLOW: + } + case BUFFER_UNDERFLOW: { throw new IllegalStateException("Unexpected ssl engine result"); - case CLOSED: + } + case CLOSED: { try { return EMPTY_BUFFER; } catch (Exception e) { - LOGGER.error("Failed to send server's CLOSE message due to socket channel's failure."); + log.error("Failed to send server's CLOSE message due to socket channel's failure."); handshakeStatus = sslEngine.getHandshakeStatus(); } break; - default: + } + default: { throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } } break; - case NEED_TASK: + } + case NEED_TASK: { Runnable task; while ((task = sslEngine.getDelegatedTask()) != null) { - LOGGER.debug(task, t -> "Execute SSL Engine's task: " + t.getClass()); + log.debug(task, "Execute SSL Engine's task:[%s]"::formatted); task.run(); } handshakeStatus = sslEngine.getHandshakeStatus(); break; - case NEED_UNWRAP: + } + case NEED_UNWRAP: { break; - default: + } + default: { throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); + } } } @@ -203,7 +200,7 @@ private void increaseNetworkBuffer() { protected void closeConnection() { try { sslEngine.closeOutbound(); - channel.close(); + socketChannel.close(); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractWritableNetworkPacket.java new file mode 100644 index 00000000..7bf754f6 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractWritableNetworkPacket.java @@ -0,0 +1,106 @@ +package javasabr.rlib.network.packet.impl; + +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import javasabr.rlib.network.packet.WritableNetworkPacket; +import lombok.CustomLog; + +/** + * The base implementation of the {@link WritableNetworkPacket}. + * + * @author JavaSaBr + */ +@CustomLog +public abstract class AbstractWritableNetworkPacket extends AbstractNetworkPacket + implements WritableNetworkPacket { + + @Override + public boolean write(ByteBuffer buffer) { + try { + writeImpl(buffer); + return true; + } catch (Exception e) { + handleException(buffer, e); + return false; + } + } + + /** + * The process of writing this packet to the buffer. + */ + protected void writeImpl(ByteBuffer buffer) {} + + /** + * Write 1 byte to the buffer. + */ + protected void writeByte(ByteBuffer buffer, int value) { + buffer.put((byte) value); + } + + /** + * Write 2 bytes to the buffer. + */ + protected void writeChar(ByteBuffer buffer, char value) { + buffer.putChar(value); + } + + /** + * Write 2 bytes to the buffer. + */ + protected void writeChar(ByteBuffer buffer, int value) { + buffer.putChar((char) value); + } + + /** + * Write 4 bytes to the buffer. + */ + protected void writeFloat(ByteBuffer buffer, float value) { + buffer.putFloat(value); + } + + /** + * Write 4 bytes to the buffer. + */ + protected void writeInt(ByteBuffer buffer, int value) { + buffer.putInt(value); + } + + /** + * Write 8 bytes to the buffer. + */ + protected void writeLong(ByteBuffer buffer, long value) { + buffer.putLong(value); + } + + /** + * Writes 2 bytes to the buffer. + */ + protected void writeShort(ByteBuffer buffer, int value) { + buffer.putShort((short) value); + } + + /** + * Writes the string to the buffer. + */ + protected void writeString(ByteBuffer buffer, String string) { + try { + writeInt(buffer, string.length()); + for (int i = 0, length = string.length(); i < length; i++) { + buffer.putChar(string.charAt(i)); + } + } catch (BufferOverflowException ex) { + log.error( + string.length(), + buffer, + "Cannot write string to buffer because the string is too long. String length:[%s], buffer:[%s]"::formatted); + throw ex; + } + } + + /** + * Write a data buffer to packet buffer. + */ + protected void writeBuffer(ByteBuffer buffer, ByteBuffer data) { + buffer.put(data.array(), data.position(), data.limit()); + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractWritablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractWritablePacket.java deleted file mode 100644 index d2c9444d..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractWritablePacket.java +++ /dev/null @@ -1,30 +0,0 @@ -package javasabr.rlib.network.packet.impl; - -import java.nio.ByteBuffer; -import javasabr.rlib.network.packet.WritablePacket; - -/** - * The base implementation of the {@link WritablePacket}. - * - * @author JavaSaBr - */ -public abstract class AbstractWritablePacket extends AbstractPacket implements WritablePacket { - - @Override - public boolean write(ByteBuffer buffer) { - try { - writeImpl(buffer); - return true; - } catch (Exception e) { - handleException(buffer, e); - return false; - } - } - - /** - * The process of writing this packet to the buffer. - * - * @param buffer the buffer - */ - protected void writeImpl(ByteBuffer buffer) {} -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketReader.java similarity index 53% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultPacketReader.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketReader.java index 2bcb97e4..cef13e9c 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketReader.java @@ -2,11 +2,13 @@ import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; +import java.util.function.Consumer; import java.util.function.IntFunction; -import javasabr.rlib.common.function.NotNullConsumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.ReadablePacket; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** @@ -14,23 +16,24 @@ * @param the connections' type. * @author JavaSaBR */ -public class DefaultPacketReader> extends - AbstractPacketReader { +@FieldDefaults(level = AccessLevel.PROTECTED) +public class DefaultNetworkPacketReader> + extends AbstractNetworkPacketReader { - private final IntFunction readPacketFactory; - private final int packetLengthHeaderSize; + final IntFunction readablePacketFactory; + final int packetLengthHeaderSize; - public DefaultPacketReader( + public DefaultNetworkPacketReader( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NotNullConsumer readPacketHandler, - IntFunction readPacketFactory, + Consumer packetHandler, + IntFunction readablePacketFactory, int packetLengthHeaderSize, int maxPacketsByRead) { - super(connection, channel, bufferAllocator, updateActivityFunction, readPacketHandler, maxPacketsByRead); - this.readPacketFactory = readPacketFactory; + super(connection, channel, bufferAllocator, updateActivityFunction, packetHandler, maxPacketsByRead); + this.readablePacketFactory = readablePacketFactory; this.packetLengthHeaderSize = packetLengthHeaderSize; } @@ -40,16 +43,17 @@ protected boolean canStartReadPacket(ByteBuffer buffer) { } @Override - protected int readPacketLength(ByteBuffer buffer) { + protected int readFullPacketLength(ByteBuffer buffer) { return readHeader(buffer, packetLengthHeaderSize); } + @Nullable @Override - protected @Nullable R createPacketFor( + protected R createPacketFor( ByteBuffer buffer, int startPacketPosition, - int packetLength, - int dataLength) { - return readPacketFactory.apply(dataLength); + int packetFullLength, + int packetDataLength) { + return readablePacketFactory.apply(packetDataLength); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketWriter.java similarity index 64% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultPacketWriter.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketWriter.java index ea6a8470..c8223853 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketWriter.java @@ -2,29 +2,32 @@ import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; -import javasabr.rlib.common.function.NotNullBiConsumer; -import javasabr.rlib.common.function.NotNullConsumer; -import javasabr.rlib.common.function.NullableSupplier; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; /** * @author JavaSaBr */ -public class DefaultPacketWriter> extends - AbstractPacketWriter { +@FieldDefaults(level = AccessLevel.PROTECTED) +public class DefaultNetworkPacketWriter> + extends AbstractNetworkPacketWriter { - protected final int packetLengthHeaderSize; + final int packetLengthHeaderSize; - public DefaultPacketWriter( + public DefaultNetworkPacketWriter( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NullableSupplier nextWritePacketSupplier, - NotNullConsumer writtenPacketHandler, - NotNullBiConsumer sentPacketHandler, + Supplier nextWritePacketSupplier, + Consumer writtenPacketHandler, + BiConsumer sentPacketHandler, int packetLengthHeaderSize) { super( connection, @@ -38,7 +41,7 @@ public DefaultPacketWriter( } @Override - protected int getTotalSize(WritablePacket packet, int expectedLength) { + protected int totalSize(WritableNetworkPacket packet, int expectedLength) { return expectedLength + packetLengthHeaderSize; } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadableNetworkPacket.java new file mode 100644 index 00000000..98372a57 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadableNetworkPacket.java @@ -0,0 +1,13 @@ +package javasabr.rlib.network.packet.impl; + +/** + * @author JavaSaBr + */ +public class DefaultReadableNetworkPacket extends + AbstractIdBasedReadableNetworkPacket { + + @Override + public DefaultReadableNetworkPacket newInstance() { + return new DefaultReadableNetworkPacket(); + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadablePacket.java deleted file mode 100644 index 2246885c..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadablePacket.java +++ /dev/null @@ -1,10 +0,0 @@ -package javasabr.rlib.network.packet.impl; - -import javasabr.rlib.network.impl.DefaultConnection; - -/** - * @author JavaSaBr - */ -public class DefaultReadablePacket extends AbstractIdBasedReadablePacket { - -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSSLPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketReader.java similarity index 73% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSSLPacketReader.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketReader.java index 814eaf51..f4ec8026 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSSLPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketReader.java @@ -6,8 +6,8 @@ import javasabr.rlib.common.function.NotNullConsumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.ReadablePacket; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.ReadableNetworkPacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; import javax.net.ssl.SSLEngine; import org.jspecify.annotations.Nullable; @@ -16,13 +16,13 @@ * @param the connections' type. * @author JavaSaBR */ -public class DefaultSSLPacketReader> extends - AbstractSSLPacketReader { +public class DefaultSslNetworkPacketReader> extends + AbstractSslNetworkPacketReader { private final IntFunction readPacketFactory; private final int packetLengthHeaderSize; - public DefaultSSLPacketReader( + public DefaultSslNetworkPacketReader( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, @@ -30,7 +30,7 @@ public DefaultSSLPacketReader( NotNullConsumer readPacketHandler, IntFunction readPacketFactory, SSLEngine sslEngine, - NotNullConsumer packetWriter, + NotNullConsumer packetWriter, int packetLengthHeaderSize, int maxPacketsByRead) { super( @@ -52,7 +52,7 @@ protected boolean canStartReadPacket(ByteBuffer buffer) { } @Override - protected int readPacketLength(ByteBuffer buffer) { + protected int readFullPacketLength(ByteBuffer buffer) { return readHeader(buffer, packetLengthHeaderSize); } @@ -60,8 +60,8 @@ protected int readPacketLength(ByteBuffer buffer) { protected @Nullable R createPacketFor( ByteBuffer buffer, int startPacketPosition, - int packetLength, - int dataLength) { - return readPacketFactory.apply(dataLength); + int packetFullLength, + int packetDataLength) { + return readPacketFactory.apply(packetDataLength); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSSLPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketWriter.java similarity index 72% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSSLPacketWriter.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketWriter.java index 588b09ac..ed8f2fda 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSSLPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketWriter.java @@ -7,28 +7,28 @@ import javasabr.rlib.common.function.NullableSupplier; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; import javax.net.ssl.SSLEngine; /** * @author JavaSaBr */ -public class DefaultSSLPacketWriter> extends - AbstractSSLPacketWriter { +public class DefaultSslNetworkPacketWriter> extends + AbstractSslNetworkPacketWriter { protected final int packetLengthHeaderSize; - public DefaultSSLPacketWriter( + public DefaultSslNetworkPacketWriter( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NullableSupplier nextWritePacketSupplier, - NotNullConsumer writtenPacketHandler, - NotNullBiConsumer sentPacketHandler, + NullableSupplier nextWritePacketSupplier, + NotNullConsumer writtenPacketHandler, + NotNullBiConsumer sentPacketHandler, SSLEngine sslEngine, - NotNullConsumer packetWriter, - NotNullConsumer queueAtFirst, + NotNullConsumer packetWriter, + NotNullConsumer queueAtFirst, int packetLengthHeaderSize) { super( connection, @@ -45,7 +45,7 @@ public DefaultSSLPacketWriter( } @Override - protected int getTotalSize(WritablePacket packet, int expectedLength) { + protected int totalSize(WritableNetworkPacket packet, int expectedLength) { return expectedLength + packetLengthHeaderSize; } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultWritableNetworkPacket.java new file mode 100644 index 00000000..c134ac95 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultWritableNetworkPacket.java @@ -0,0 +1,9 @@ +package javasabr.rlib.network.packet.impl; + +import javasabr.rlib.network.packet.IdBasedWritableNetworkPacket; + +/** + * @author JavaSaBr + */ +public class DefaultWritableNetworkPacket extends AbstractWritableNetworkPacket implements + IdBasedWritableNetworkPacket {} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultWritablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultWritablePacket.java deleted file mode 100644 index 63753ed3..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultWritablePacket.java +++ /dev/null @@ -1,8 +0,0 @@ -package javasabr.rlib.network.packet.impl; - -import javasabr.rlib.network.packet.IdBasedWritablePacket; - -/** - * @author JavaSaBr - */ -public class DefaultWritablePacket extends AbstractWritablePacket implements IdBasedWritablePacket {} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedNetworkPacketWriter.java similarity index 60% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketWriter.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedNetworkPacketWriter.java index 62ec9c39..87cb4c44 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedNetworkPacketWriter.java @@ -7,25 +7,25 @@ import javasabr.rlib.common.function.NullableSupplier; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.IdBasedWritablePacket; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.IdBasedWritableNetworkPacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; /** * @author JavaSaBr */ -public class IdBasedPacketWriter> extends - DefaultPacketWriter { +public class IdBasedNetworkPacketWriter> extends + DefaultNetworkPacketWriter { protected final int packetIdHeaderSize; - public IdBasedPacketWriter( + public IdBasedNetworkPacketWriter( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NullableSupplier nextWritePacketSupplier, - NotNullConsumer writtenPacketHandler, - NotNullBiConsumer sentPacketHandler, + NullableSupplier nextWritePacketSupplier, + NotNullConsumer writtenPacketHandler, + NotNullBiConsumer sentPacketHandler, int packetLengthHeaderSize, int packetIdHeaderSize) { super( @@ -41,13 +41,13 @@ public IdBasedPacketWriter( } @Override - protected boolean onWrite( + protected boolean write( W packet, int expectedLength, int totalSize, ByteBuffer firstBuffer, ByteBuffer secondBuffer) { - writeHeader(firstBuffer, packet.getPacketId(), packetIdHeaderSize); - return super.onWrite(packet, expectedLength, totalSize, firstBuffer, secondBuffer); + writeHeader(firstBuffer, packet.packetId(), packetIdHeaderSize); + return super.write(packet, expectedLength, totalSize, firstBuffer, secondBuffer); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketReader.java index e4585319..029f5708 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketReader.java @@ -5,8 +5,8 @@ import javasabr.rlib.common.function.NotNullConsumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; -import javasabr.rlib.network.packet.IdBasedReadablePacket; -import javasabr.rlib.network.packet.registry.ReadablePacketRegistry; +import javasabr.rlib.network.packet.IdBasedReadableNetworkPacket; +import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; import org.jspecify.annotations.Nullable; /** @@ -14,10 +14,10 @@ * @param the connection's type. * @author JavaSaBr */ -public class IdBasedPacketReader, C extends Connection> extends - AbstractPacketReader { +public class IdBasedPacketReader, C extends Connection> extends + AbstractNetworkPacketReader { - private final ReadablePacketRegistry packetRegistry; + private final ReadableNetworkPacketRegistry packetRegistry; private final int packetLengthHeaderSize; private final int packetIdHeaderSize; @@ -30,7 +30,7 @@ public IdBasedPacketReader( int packetLengthHeaderSize, int maxPacketsByRead, int packetIdHeaderSize, - ReadablePacketRegistry packetRegistry) { + ReadableNetworkPacketRegistry packetRegistry) { super(connection, channel, bufferAllocator, updateActivityFunction, readPacketHandler, maxPacketsByRead); this.packetLengthHeaderSize = packetLengthHeaderSize; this.packetIdHeaderSize = packetIdHeaderSize; @@ -43,7 +43,7 @@ protected boolean canStartReadPacket(ByteBuffer buffer) { } @Override - protected int readPacketLength(ByteBuffer buffer) { + protected int readFullPacketLength(ByteBuffer buffer) { return readHeader(buffer, packetLengthHeaderSize); } @@ -51,10 +51,10 @@ protected int readPacketLength(ByteBuffer buffer) { protected @Nullable R createPacketFor( ByteBuffer buffer, int startPacketPosition, - int packetLength, - int dataLength) { + int packetFullLength, + int packetDataLength) { return packetRegistry - .findById(readHeader(buffer, packetIdHeaderSize)) + .resolvePrototypeById(readHeader(buffer, packetIdHeaderSize)) .newInstance(); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SSLWritablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SSLWritablePacket.java deleted file mode 100644 index f989d60c..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SSLWritablePacket.java +++ /dev/null @@ -1,20 +0,0 @@ -package javasabr.rlib.network.packet.impl; - -import java.nio.ByteBuffer; - -/** - * Packet marker. - */ -public class SSLWritablePacket extends AbstractWritablePacket { - - private static final SSLWritablePacket INSTANCE = new SSLWritablePacket(); - - public static SSLWritablePacket getInstance() { - return INSTANCE; - } - - @Override - public boolean write(ByteBuffer buffer) { - return true; - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWritableNetworkPacket.java new file mode 100644 index 00000000..418b95c0 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWritableNetworkPacket.java @@ -0,0 +1,20 @@ +package javasabr.rlib.network.packet.impl; + +import java.nio.ByteBuffer; + +/** + * Packet marker. + */ +public class SslWritableNetworkPacket extends AbstractWritableNetworkPacket { + + private static final SslWritableNetworkPacket INSTANCE = new SslWritableNetworkPacket(); + + public static SslWritableNetworkPacket getInstance() { + return INSTANCE; + } + + @Override + public boolean write(ByteBuffer buffer) { + return true; + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java index 6f8911d1..f66d229b 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java @@ -9,7 +9,7 @@ * @author JavaSaBr */ @Getter -public class StringReadablePacket extends AbstractReadablePacket> { +public class StringReadablePacket extends AbstractReadableNetworkPacket> { /** * Read data. diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java similarity index 81% rename from rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritablePacket.java rename to rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java index 20d9eea3..96aa4fe8 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java @@ -7,7 +7,7 @@ * @author JavaSaBr */ @RequiredArgsConstructor -public class StringWritablePacket extends AbstractWritablePacket { +public class StringWritableNetworkPacket extends AbstractWritableNetworkPacket { private final String data; @@ -18,7 +18,7 @@ protected void writeImpl(ByteBuffer buffer) { } @Override - public int getExpectedLength() { + public int expectedLength() { return 4 + data.length() * 2; } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/WritablePacketWrapper.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/WritablePacketWrapper.java index 2aa320fa..668e1ba1 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/WritablePacketWrapper.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/WritablePacketWrapper.java @@ -1,7 +1,7 @@ package javasabr.rlib.network.packet.impl; import java.nio.ByteBuffer; -import javasabr.rlib.network.packet.WritablePacket; +import javasabr.rlib.network.packet.WritableNetworkPacket; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -13,7 +13,8 @@ */ @Getter @RequiredArgsConstructor -public class WritablePacketWrapper implements WritablePacket { +public class WritablePacketWrapper + implements WritableNetworkPacket { private final A attachment; private final W packet; @@ -24,12 +25,12 @@ public boolean write(ByteBuffer buffer) { } @Override - public int getExpectedLength() { - return packet.getExpectedLength(); + public int expectedLength() { + return packet.expectedLength(); } @Override - public String getName() { + public String name() { return "WritablePacketWrapper"; } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadableNetworkPacketRegistry.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadableNetworkPacketRegistry.java new file mode 100644 index 00000000..af8b0223 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadableNetworkPacketRegistry.java @@ -0,0 +1,106 @@ +package javasabr.rlib.network.packet.registry; + +import javasabr.rlib.classpath.ClassPathScanner; +import javasabr.rlib.classpath.ClassPathScannerFactory; +import javasabr.rlib.collections.array.Array; +import javasabr.rlib.collections.array.ArrayCollectors; +import javasabr.rlib.network.annotation.NetworkPacketDescription; +import javasabr.rlib.network.packet.IdBasedReadableNetworkPacket; +import javasabr.rlib.network.packet.registry.impl.IdBasedReadableNetworkPacketRegistry; + +/** + * The interface to implement a registry of readable packets. + * + * @author JavaSaBr + */ +public interface ReadableNetworkPacketRegistry> { + + /** + * Creates a new empty readable packet registry. + */ + static ReadableNetworkPacketRegistry empty() { + return new IdBasedReadableNetworkPacketRegistry<>(IdBasedReadableNetworkPacket.class); + } + + /** + * Create a new empty readable packet registry. + */ + static > ReadableNetworkPacketRegistry empty(Class type) { + return new IdBasedReadableNetworkPacketRegistry<>(type); + } + + /** + * Creates a new class path scanning based readable packet registry. + */ + static ReadableNetworkPacketRegistry classPathBased() { + + var scanner = ClassPathScannerFactory.newDefaultScanner(); + scanner.useSystemClassPath(true); + scanner.scan(); + + return of(scanner); + } + + /** + * Creates a new class path scanning based readable packet registry by scanning the main class. + */ + static ReadableNetworkPacketRegistry classPathBased(Class mainClass) { + + var scanner = ClassPathScannerFactory.newManifestScanner(mainClass); + scanner.useSystemClassPath(false); + scanner.scan(); + + return of(scanner); + } + + /** + * Creates a new class path scanning based readable packet registry. + */ + static ReadableNetworkPacketRegistry of(ClassPathScanner scanner) { + + var result = scanner + .findImplementations(IdBasedReadableNetworkPacket.class) + .stream() + .filter(type -> type.getAnnotation(NetworkPacketDescription.class) != null) + .collect(ArrayCollectors.>toArray(Class.class)); + + var registry = new IdBasedReadableNetworkPacketRegistry<>(IdBasedReadableNetworkPacket.class); + registry.register(result); + + return registry; + } + + /** + * Creates a new readable packet registry. + */ + @SafeVarargs + static > ReadableNetworkPacketRegistry of( + Class type, + Class... classes) { + var registry = new IdBasedReadableNetworkPacketRegistry<>(type); + registry.register(classes, classes.length); + return registry; + } + + /** + * Creates a new readable packet registry. + */ + static > ReadableNetworkPacketRegistry of( + Class type, + Array> classes) { + + var registry = new IdBasedReadableNetworkPacketRegistry<>(type); + registry.register(classes); + + return registry; + } + + /** + * Resolve a network packet prototype based on packet id. + * + * @param id the network packet id. + * @return the resolve prototype. + * @throws IllegalArgumentException if can't resolve a prototype by the id. + */ + R resolvePrototypeById(int id); +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java deleted file mode 100644 index 89595677..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadablePacketRegistry.java +++ /dev/null @@ -1,130 +0,0 @@ -package javasabr.rlib.network.packet.registry; - -import javasabr.rlib.classpath.ClassPathScanner; -import javasabr.rlib.classpath.ClassPathScannerFactory; -import javasabr.rlib.collections.array.Array; -import javasabr.rlib.collections.array.ArrayCollectors; -import javasabr.rlib.network.annotation.PacketDescription; -import javasabr.rlib.network.packet.IdBasedReadablePacket; -import javasabr.rlib.network.packet.registry.impl.IdBasedReadablePacketRegistry; - -/** - * The interface to implement a registry of readable packets. - * - * @author JavaSaBr - */ -public interface ReadablePacketRegistry> { - - /** - * Create a new empty readable packet registry. - * - * @return the new packet registry. - */ - static ReadablePacketRegistry empty() { - return new IdBasedReadablePacketRegistry<>(IdBasedReadablePacket.class); - } - - /** - * Create a new empty readable packet registry. - * - * @param type the packet's type. - * @param the packet's type. - * @return the new packet registry. - */ - static > ReadablePacketRegistry empty(Class type) { - return new IdBasedReadablePacketRegistry<>(type); - } - - /** - * Create a new default readable packet registry. - * - * @return the new packet registry. - */ - static ReadablePacketRegistry newDefault() { - - var scanner = ClassPathScannerFactory.newDefaultScanner(); - scanner.useSystemClassPath(true); - scanner.scan(); - - return of(scanner); - } - - /** - * Create a new default readable packet registry by the result of scanning classpath of the main class. - * - * @param mainClass the main class of application. - * @return the new packet registry. - */ - static ReadablePacketRegistry newDefault(Class mainClass) { - - var scanner = ClassPathScannerFactory.newManifestScanner(mainClass); - scanner.useSystemClassPath(false); - scanner.scan(); - - return of(scanner); - } - - /** - * Creates a new default readable packet registry by the classpath scanner. - * - * @param scanner the classpath scanner. - * @return the new packet registry. - */ - static ReadablePacketRegistry of(ClassPathScanner scanner) { - - var result = scanner - .findImplementations(IdBasedReadablePacket.class) - .stream() - .filter(type -> type.getAnnotation(PacketDescription.class) != null) - .collect(ArrayCollectors.>toArray(Class.class)); - - var registry = new IdBasedReadablePacketRegistry<>(IdBasedReadablePacket.class); - registry.register(result); - - return registry; - } - - /** - * Create a new readable packet registry by array of classes. - * - * @param type the base packet's type. - * @param classes the classes array. - * @param the packet's type. - * @return the new packet registry. - */ - @SafeVarargs - static > ReadablePacketRegistry of( - Class type, - Class... classes) { - var registry = new IdBasedReadablePacketRegistry<>(type); - registry.register(classes, classes.length); - return registry; - } - - /** - * Create a new readable packet registry by array of classes. - * - * @param type the base packet's type. - * @param classes the classes array. - * @param the packet's type. - * @return the new packet registry. - */ - static > ReadablePacketRegistry of( - Class type, - Array> classes) { - - var registry = new IdBasedReadablePacketRegistry<>(type); - registry.register(classes); - - return registry; - } - - /** - * Find a packet by the id. - * - * @param id the packet id. - * @return the packet. - * @throws IllegalArgumentException if can't find a packet by the id. - */ - R findById(int id); -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/impl/IdBasedReadableNetworkPacketRegistry.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/impl/IdBasedReadableNetworkPacketRegistry.java new file mode 100644 index 00000000..815911c2 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/impl/IdBasedReadableNetworkPacketRegistry.java @@ -0,0 +1,168 @@ +package javasabr.rlib.network.packet.registry.impl; + +import java.util.Arrays; +import java.util.Optional; +import java.util.function.Supplier; +import javasabr.rlib.collections.array.Array; +import javasabr.rlib.common.util.ArrayUtils; +import javasabr.rlib.common.util.ClassUtils; +import javasabr.rlib.common.util.ObjectUtils; +import javasabr.rlib.network.annotation.NetworkPacketDescription; +import javasabr.rlib.network.packet.IdBasedReadableNetworkPacket; +import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; +import lombok.AccessLevel; +import lombok.CustomLog; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; + +/** + * Id based implementation of readable network packet's registry. + * + * @author JavaSaBr + */ +@CustomLog +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +public class IdBasedReadableNetworkPacketRegistry> + implements ReadableNetworkPacketRegistry { + + @Getter(AccessLevel.PROTECTED) + final Class type; + + @Getter(AccessLevel.PROTECTED) + final @Nullable R[] idToPrototype; + + public IdBasedReadableNetworkPacketRegistry(Class type) { + this.idToPrototype = ArrayUtils.create(type, 0); + this.type = type; + } + + /** + * Registers classes of readable network packets. + * + * @throws IllegalArgumentException if found a class without description annotation or if found duplication by id. + */ + public IdBasedReadableNetworkPacketRegistry register(Array> classes) { + return register(classes.toArray(), classes.size()); + } + + /** + * Registers classes of readable network packets. + * + * @throws IllegalArgumentException if found a class without description annotation or if found duplication by id. + * id. + */ + @SafeVarargs + public final IdBasedReadableNetworkPacketRegistry register(Class... classes) { + return register(classes, classes.length); + } + + /** + * Registers classes of readable network packets. + * + * @throws IllegalArgumentException if found a class without description annotation or if found duplication by id. + */ + public IdBasedReadableNetworkPacketRegistry register(Class[] classes, int length) { + + Optional> incorrectClass = Arrays + .stream(classes, 0, length) + .filter(type -> type.getAnnotation(NetworkPacketDescription.class) == null) + .findFirst(); + + if (incorrectClass.isPresent()) { + throw new IllegalArgumentException("Have found class:[%s] without description annotation".formatted(incorrectClass.get())); + } + + int maxId = Arrays + .stream(classes, 0, length) + .map(type -> type.getAnnotation(NetworkPacketDescription.class)) + .mapToInt(NetworkPacketDescription::id) + .max() + .orElseThrow(() -> new IllegalStateException("Not found any packet id")); + + @Nullable R[] idToPrototype = ArrayUtils.create(type, maxId + 1); + + for (int i = 0; i < length; i++) { + Class cs = classes[i]; + if (!type.isAssignableFrom(cs)) { + log.warning(cs, type, "Found incompatibility packet's type:[%s] with type:[%s]"::formatted); + continue; + } + + var description = cs.getAnnotation(NetworkPacketDescription.class); + var id = description.id(); + + R exist = idToPrototype[id]; + if (exist != null) { + throw new IllegalArgumentException("Found duplication by id:[%d], existed packet is:[%s], new packet is:[%s]" + .formatted(id, exist.getClass(), cs)); + } + + idToPrototype[id] = ClassUtils.newInstance(cs); + } + + return new IdBasedReadableNetworkPacketRegistry<>(type, idToPrototype); + } + + /** + * Registers a class of readable network packet. + * + * @throws IllegalArgumentException if this class doesn't have {@link NetworkPacketDescription}, wrong id or some class is + * already presented with the same id. + */ + public IdBasedReadableNetworkPacketRegistry register(Class cs) { + return register(cs, () -> ClassUtils.newInstance(cs)); + } + + /** + * Registers a class of readable packet. + * + * @return the reference to this registry. + * @throws IllegalArgumentException if this class doesn't have {@link NetworkPacketDescription}, wrong id or some class is + * already presented with the same id. + */ + public

IdBasedReadableNetworkPacketRegistry register(Class

cs, Supplier

factory) { + + var description = cs.getAnnotation(NetworkPacketDescription.class); + if (description == null) { + throw new IllegalArgumentException("Class:[%s] doesn't have description annotation.".formatted(cs)); + } + + var id = description.id(); + if (id < 0) { + throw new IllegalArgumentException("Class:[%s] has unexpected packet id:[%d]".formatted(cs, id)); + } + + @Nullable R[] idToPrototype = idToPrototype(); + + if (id < idToPrototype.length) { + R exist = idToPrototype[id]; + if (exist != null) { + throw new IllegalArgumentException("Class:[%s] is already has the same id:[%d]" + .formatted(exist.getClass(), id)); + } else { + idToPrototype = ArrayUtils.copyOf(idToPrototype); + idToPrototype[id] = ClassUtils.newInstance(cs); + return new IdBasedReadableNetworkPacketRegistry<>(type, idToPrototype); + } + } + + idToPrototype = Arrays.copyOf(idToPrototype, id + 1); + idToPrototype[id] = factory.get(); + + return new IdBasedReadableNetworkPacketRegistry<>(type, idToPrototype); + } + + @Override + public R resolvePrototypeById(int id) { + try { + return ObjectUtils.notNull(idToPrototype[id], id, integer -> new IllegalArgumentException("Not found a packet for the id " + integer)); + } catch (IndexOutOfBoundsException e) { + throw new IllegalArgumentException("Not found prototype for the id " + id); + } + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/impl/IdBasedReadablePacketRegistry.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/impl/IdBasedReadablePacketRegistry.java deleted file mode 100644 index 1ed08492..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/impl/IdBasedReadablePacketRegistry.java +++ /dev/null @@ -1,201 +0,0 @@ -package javasabr.rlib.network.packet.registry.impl; - -import java.util.Arrays; -import java.util.function.Supplier; -import javasabr.rlib.collections.array.Array; -import javasabr.rlib.common.util.ArrayUtils; -import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import javasabr.rlib.network.annotation.PacketDescription; -import javasabr.rlib.network.packet.IdBasedReadablePacket; -import javasabr.rlib.network.packet.registry.ReadablePacketRegistry; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; - -/** - * The id based implementation of readable packets registry. - * - * @author JavaSaBr - */ -public class IdBasedReadablePacketRegistry> implements ReadablePacketRegistry { - - private static final Logger LOGGER = LoggerManager.getLogger(IdBasedReadablePacketRegistry.class); - - /** - * The packet's type in this registry. - */ - private final Class type; - - /** - * The array of packet id to packet instance. - */ - @Getter(AccessLevel.PRIVATE) - @Setter(AccessLevel.PRIVATE) - private volatile R[] idToPacket; - - public IdBasedReadablePacketRegistry(Class type) { - this.idToPacket = ArrayUtils.create(type, 0); - this.type = type; - } - - /** - * Register classes of readable packets. - * - * @param classes the classes array. - * @return the reference to this registry. - * @throws IllegalArgumentException if found a class without packet description annotation or if found duplication by - * id. - */ - public IdBasedReadablePacketRegistry register(Array> classes) { - return register(classes.toArray(), classes.size()); - } - - /** - * Register classes of readable packets. - * - * @param classes the classes array. - * @return the reference to this registry. - * @throws IllegalArgumentException if found a class without packet description annotation or if found duplication by - * id. - */ - @SafeVarargs - public final IdBasedReadablePacketRegistry register(Class... classes) { - return register(classes, classes.length); - } - - /** - * Register classes of readable packets. - * - * @param classes the classes array. - * @param length the length of the classes. - * @return the reference to this registry. - * @throws IllegalArgumentException if found a class without packet description annotation or if found duplication by - * id. - */ - public IdBasedReadablePacketRegistry register(Class[] classes, int length) { - - var incorrectClass = Arrays - .stream(classes, 0, length) - .filter(type -> type.getAnnotation(PacketDescription.class) == null) - .findFirst(); - - if (incorrectClass.isPresent()) { - throw new IllegalArgumentException( - "Have found a class " + incorrectClass.get() + " without the packet description annotation."); - } - - var maxId = Arrays - .stream(classes, 0, length) - .map(type -> type.getAnnotation(PacketDescription.class)) - .mapToInt(PacketDescription::id) - .max() - .orElseThrow(() -> new IllegalStateException("Not found any packet id")); - - setIdToPacket(Arrays.copyOf(getIdToPacket(), maxId + 1)); - - var idToPacket = getIdToPacket(); - - for (int i = 0; i < length; i++) { - - var cs = classes[i]; - - if (!type.isAssignableFrom(cs)) { - LOGGER.warning( - cs, - type, - (detected, check) -> "Found incompatibility packet's type: " + detected + " with type: " + check); - continue; - } - - var description = cs.getAnnotation(PacketDescription.class); - var id = description.id(); - - if (idToPacket[id] != null) { - throw new IllegalArgumentException( - "Have found duplication by id " + id + ", existed packet is " + idToPacket[id].getClass() - + ", new packet is " + cs); - } - - idToPacket[id] = ClassUtils.newInstance(cs); - } - - return this; - } - - /** - * Register a class of readable packet. - * - * @param cs the class. - * @return the reference to this registry. - * @throws IllegalArgumentException if this class doesn't have {@link PacketDescription}, wrong id or some class is - * already presented with the same id. - */ - public IdBasedReadablePacketRegistry register(Class cs) { - return register(cs, () -> ClassUtils.newInstance(cs)); - } - - /** - * Register a class of readable packet. - * - * @param cs the class. - * @param factory the instance factory. - * @param

the packet's type. - * @return the reference to this registry. - * @throws IllegalArgumentException if this class doesn't have {@link PacketDescription}, wrong id or some class is - * already presented with the same id. - */ - public

IdBasedReadablePacketRegistry register( - Class

cs, - Supplier

factory) { - - var description = cs.getAnnotation(PacketDescription.class); - - if (description == null) { - throw new IllegalArgumentException("Class " + cs + " doesn't have packet description annotation."); - } - - var id = description.id(); - - if (id < 0) { - throw new IllegalArgumentException("Class " + cs + " has wrong packet id: " + id); - } - - var idToPacket = getIdToPacket(); - - if (id < idToPacket.length) { - if (idToPacket[id] != null) { - throw new IllegalArgumentException("Class " + idToPacket[id].getClass() + " is already has the same id: " + id); - } else { - idToPacket[id] = ClassUtils.newInstance(cs); - return this; - } - } - - idToPacket = Arrays.copyOf(getIdToPacket(), id + 1); - idToPacket[id] = factory.get(); - - setIdToPacket(idToPacket); - - return this; - } - - @Override - public R findById(int id) { - - R[] idToPacket = getIdToPacket(); - - if (id < 0 || id >= idToPacket.length) { - throw new IllegalArgumentException("Not found a packet for the id " + id); - } - - var packet = idToPacket[id]; - - if (packet == null) { - throw new IllegalArgumentException("Not found a packet for the id " + id); - } - - return packet; - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/server/ServerNetwork.java b/rlib-network/src/main/java/javasabr/rlib/network/server/ServerNetwork.java index 877cd9ac..1fa6aa30 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/server/ServerNetwork.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/server/ServerNetwork.java @@ -15,31 +15,21 @@ public interface ServerNetwork> extends Network { /** * Start a server using any available address. - * - * @return this server's address. */ InetSocketAddress start(); /** * Start a server by the address. - * - * @param serverAddress the sever address. - * @param the server network's type. - * @return this network. */ > S start(InetSocketAddress serverAddress); /** * Register a consumer of new connections. - * - * @param consumer the consumer of new connections. */ void onAccept(Consumer consumer); /** * Get a stream of new accepted connections. - * - * @return the stream of new accepted connections. */ Flux accepted(); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/server/impl/DefaultServerNetwork.java b/rlib-network/src/main/java/javasabr/rlib/network/server/impl/DefaultServerNetwork.java index 579a04ea..46e6e2a2 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/server/impl/DefaultServerNetwork.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/server/impl/DefaultServerNetwork.java @@ -1,7 +1,5 @@ package javasabr.rlib.network.server.impl; -import static javasabr.rlib.common.util.Utils.uncheckedGet; - import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.AcceptPendingException; @@ -11,6 +9,7 @@ import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; @@ -22,14 +21,15 @@ import javasabr.rlib.common.util.ClassUtils; import javasabr.rlib.common.util.GroupThreadFactory; import javasabr.rlib.common.util.Utils; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.Network; import javasabr.rlib.network.ServerNetworkConfig; import javasabr.rlib.network.UnsafeConnection; import javasabr.rlib.network.impl.AbstractNetwork; import javasabr.rlib.network.server.ServerNetwork; import javasabr.rlib.network.util.NetworkUtils; +import lombok.AccessLevel; +import lombok.CustomLog; +import lombok.experimental.FieldDefaults; import reactor.core.publisher.Flux; import reactor.core.publisher.FluxSink; @@ -38,10 +38,10 @@ * * @author JavaSaBr */ -public final class DefaultServerNetwork> extends AbstractNetwork implements - ServerNetwork { - - protected static final Logger LOGGER = LoggerManager.getLogger(DefaultServerNetwork.class); +@CustomLog +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) +public class DefaultServerNetwork> + extends AbstractNetwork implements ServerNetwork { private interface ServerCompletionHandler> extends CompletionHandler> {} @@ -50,8 +50,8 @@ private interface ServerCompletionHandler> exte @Override public void completed(AsynchronousSocketChannel channel, DefaultServerNetwork network) { - var connection = network.channelToConnection.apply(DefaultServerNetwork.this, channel); - LOGGER.debug(connection, conn -> "Accepted new connection: " + conn.getRemoteAddress()); + var connection = network.channelToConnection.apply(network, channel); + log.debug(connection.remoteAddress(), "Accepted new connection:[%s]"::formatted); network.onAccept(connection); network.acceptNext(); } @@ -59,11 +59,10 @@ public void completed(AsynchronousSocketChannel channel, DefaultServerNetwork @Override public void failed(Throwable exc, DefaultServerNetwork network) { if (exc instanceof AsynchronousCloseException) { - LOGGER.warning("Server network was closed"); + log.warning("Server network was closed"); } else { - LOGGER.error("Got exception during accepting new connection:"); - LOGGER.error(exc); - + log.error("Got exception during accepting new connection:"); + log.error(exc); if (channel.isOpen()) { network.acceptNext(); } @@ -71,56 +70,25 @@ public void failed(Throwable exc, DefaultServerNetwork network) { } }; - protected final AsynchronousChannelGroup group; - protected final AsynchronousServerSocketChannel channel; - protected final MutableArray> subscribers; + AsynchronousChannelGroup group; + AsynchronousServerSocketChannel channel; + MutableArray> subscribers; public DefaultServerNetwork( ServerNetworkConfig config, BiFunction, AsynchronousSocketChannel, C> channelToConnection) { - super(config, channelToConnection); - - var threadFactory = new GroupThreadFactory( - config.getThreadGroupName(), - config.getThreadConstructor(), - config.getThreadPriority(), - false); - - var executor = config.getThreadGroupMinSize() < config.getThreadGroupMaxSize() - ? new ThreadPoolExecutor( - config.getThreadGroupMinSize(), - config.getThreadGroupMaxSize(), - 120, - TimeUnit.SECONDS, - new SynchronousQueue<>(), - threadFactory, - new ThreadPoolExecutor.CallerRunsPolicy()) - : Executors.newFixedThreadPool(config.getThreadGroupMinSize(), threadFactory); - - // activate the executor - executor.submit(() -> {}); - - LOGGER.info( - config, - conf -> "Server network configuration: {\n" + " minThreads: " + conf.getThreadGroupMinSize() + ",\n" - + " maxThreads: " + conf.getThreadGroupMaxSize() + ",\n" + " priority: " + conf.getThreadPriority() - + ",\n" + " groupName: \"" + conf.getThreadGroupName() + "\",\n" + " readBufferSize: " - + conf.getReadBufferSize() + ",\n" + " pendingBufferSize: " + conf.getPendingBufferSize() + ",\n" - + " writeBufferSize: " + conf.getWriteBufferSize() + "\n" + "}"); - - this.group = uncheckedGet(executor, AsynchronousChannelGroup::withThreadPool); - this.channel = uncheckedGet(group, AsynchronousServerSocketChannel::open); + this.group = Utils.uncheckedGet(buildExecutor(config), AsynchronousChannelGroup::withThreadPool); + this.channel = Utils.uncheckedGet(group, AsynchronousServerSocketChannel::open); this.subscribers = ArrayFactory.copyOnModifyArray(Consumer.class); + log.info(config, DefaultServerNetwork::buildConfigDescription); } @Override public InetSocketAddress start() { InetSocketAddress address = null; - while (address == null) { - address = new InetSocketAddress(NetworkUtils.getAvailablePort(1500)); try { channel.bind(address); @@ -129,7 +97,7 @@ public InetSocketAddress start() { } } - LOGGER.info(address, adr -> "Started server socket on address: " + adr); + log.info(address, "Started server socket on address:[%s]"::formatted); if (!subscribers.isEmpty()) { acceptNext(); @@ -141,13 +109,10 @@ public InetSocketAddress start() { @Override public > S start(InetSocketAddress serverAddress) { Utils.unchecked(channel, serverAddress, AsynchronousServerSocketChannel::bind); - - LOGGER.info(serverAddress, addr -> "Started server socket on address: " + addr); - + log.info(serverAddress, addr -> "Started server socket on address: " + addr); if (!subscribers.isEmpty()) { acceptNext(); } - return ClassUtils.unsafeNNCast(this); } @@ -155,10 +120,9 @@ protected void acceptNext() { if (channel.isOpen()) { try { channel.accept(this, acceptHandler); - } catch (AcceptPendingException ignored) { - } + } catch (AcceptPendingException ignored) {} } else { - LOGGER.warning("Cannot accept a next connection because server channel is already closed"); + log.error("Cannot accept next connection because server channel is already closed"); } } @@ -191,4 +155,39 @@ public void shutdown() { Utils.unchecked(channel, AsynchronousChannel::close); group.shutdown(); } + + protected ExecutorService buildExecutor(ServerNetworkConfig config) { + + var threadFactory = new GroupThreadFactory( + config.threadGroupName(), + config.threadConstructor(), + config.threadPriority(), + false); + + ExecutorService executorService; + if (config.threadGroupMinSize() < config.threadGroupMaxSize()) { + executorService = new ThreadPoolExecutor( + config.threadGroupMinSize(), + config.threadGroupMaxSize(), + 120, + TimeUnit.SECONDS, + new SynchronousQueue<>(), + threadFactory, + new ThreadPoolExecutor.CallerRunsPolicy()); + } else { + executorService = Executors.newFixedThreadPool(config.threadGroupMinSize(), threadFactory); + } + + // activate the executor + executorService.submit(() -> {}); + return executorService; + } + + private static String buildConfigDescription(ServerNetworkConfig conf) { + return "Server network configuration: {\n" + " minThreads: " + conf.threadGroupMinSize() + ",\n" + " maxThreads: " + + conf.threadGroupMaxSize() + ",\n" + " priority: " + conf.threadPriority() + ",\n" + " groupName: \"" + + conf.threadGroupName() + "\",\n" + " readBufferSize: " + conf.readBufferSize() + ",\n" + + " pendingBufferSize: " + conf.pendingBufferSize() + ",\n" + " writeBufferSize: " + conf.writeBufferSize() + + "\n" + "}"; + } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java b/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java index de891beb..a5b0bdd5 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java @@ -37,11 +37,9 @@ public X509Certificate[] getAcceptedIssuers() { return EMPTY_CERTS; } - public void checkClientTrusted(X509Certificate[] certificates, String arg1) { - } + public void checkClientTrusted(X509Certificate[] certificates, String arg1) {} - public void checkServerTrusted(X509Certificate[] certificates, String arg1) { - } + public void checkServerTrusted(X509Certificate[] certificates, String arg1) {} } public static SocketAddress getRemoteAddress(AsynchronousSocketChannel socketChannel) { @@ -96,14 +94,10 @@ public static SSLContext createSslContext( } public static SSLContext createAllTrustedClientSslContext() { - try { - var sslContext = SSLContext.getInstance("TLSv1.2"); sslContext.init(null, new TrustManager[]{new AllTrustManager()}, new SecureRandom()); - return sslContext; - } catch (Exception e) { throw new RuntimeException(e); } diff --git a/rlib-network/src/test/java/javasabr/rlib/network/BaseNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/BaseNetworkTest.java index 3ccfaaeb..69b2ab70 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/BaseNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/BaseNetworkTest.java @@ -6,8 +6,8 @@ import javasabr.rlib.network.impl.DefaultConnection; import javasabr.rlib.network.impl.StringDataConnection; import javasabr.rlib.network.impl.StringDataSSLConnection; -import javasabr.rlib.network.packet.impl.DefaultReadablePacket; -import javasabr.rlib.network.packet.registry.ReadablePacketRegistry; +import javasabr.rlib.network.packet.impl.DefaultReadableNetworkPacket; +import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; import javasabr.rlib.network.server.ServerNetwork; import javax.net.ssl.SSLContext; import lombok.AllArgsConstructor; @@ -89,14 +89,14 @@ protected TestNetwork buildStringNetwork( var asyncClientToServer = new CompletableFuture(); var asyncServerToClient = new CompletableFuture(); - var serverNetwork = NetworkFactory.newStringDataServerNetwork(serverNetworkConfig, serverBufferAllocator); + var serverNetwork = NetworkFactory.stringDataServerNetwork(serverNetworkConfig, serverBufferAllocator); var serverAddress = serverNetwork.start(); serverNetwork.onAccept(asyncServerToClient::complete); - var clientNetwork = NetworkFactory.newStringDataClientNetwork(clientNetworkConfig, clientBufferAllocator); + var clientNetwork = NetworkFactory.stringDataClientNetwork(clientNetworkConfig, clientBufferAllocator); clientNetwork - .connect(serverAddress) + .connectAsync(serverAddress) .thenApply(asyncClientToServer::complete); return new TestNetwork<>( @@ -119,7 +119,7 @@ protected TestNetwork buildStringSSLNetwork( var asyncClientToServer = new CompletableFuture(); var asyncServerToClient = new CompletableFuture(); - var serverNetwork = NetworkFactory.newStringDataSSLServerNetwork( + var serverNetwork = NetworkFactory.stringDataSslServerNetwork( serverNetworkConfig, serverBufferAllocator, serverSSLContext); @@ -127,13 +127,13 @@ protected TestNetwork buildStringSSLNetwork( var serverAddress = serverNetwork.start(); serverNetwork.onAccept(asyncServerToClient::complete); - var clientNetwork = NetworkFactory.newStringDataSSLClientNetwork( + var clientNetwork = NetworkFactory.stringDataSslClientNetwork( clientNetworkConfig, clientBufferAllocator, clientSSLContext); clientNetwork - .connect(serverAddress) + .connectAsync(serverAddress) .thenApply(asyncClientToServer::complete); return new TestNetwork<>( @@ -146,8 +146,8 @@ protected TestNetwork buildStringSSLNetwork( } protected TestNetwork buildDefaultNetwork( - ReadablePacketRegistry serverPacketRegistry, - ReadablePacketRegistry clientPacketRegistry) { + ReadableNetworkPacketRegistry serverPacketRegistry, + ReadableNetworkPacketRegistry clientPacketRegistry) { return buildDefaultNetwork( ServerNetworkConfig.DEFAULT_SERVER, new DefaultBufferAllocator(ServerNetworkConfig.DEFAULT_SERVER), @@ -159,9 +159,9 @@ protected TestNetwork buildDefaultNetwork( protected TestNetwork buildDefaultNetwork( BufferAllocator serverBufferAllocator, - ReadablePacketRegistry serverPacketRegistry, + ReadableNetworkPacketRegistry serverPacketRegistry, BufferAllocator clientBufferAllocator, - ReadablePacketRegistry clientPacketRegistry) { + ReadableNetworkPacketRegistry clientPacketRegistry) { return buildDefaultNetwork( ServerNetworkConfig.DEFAULT_SERVER, serverBufferAllocator, @@ -174,15 +174,15 @@ protected TestNetwork buildDefaultNetwork( protected TestNetwork buildDefaultNetwork( ServerNetworkConfig serverNetworkConfig, BufferAllocator serverBufferAllocator, - ReadablePacketRegistry serverPacketRegistry, + ReadableNetworkPacketRegistry serverPacketRegistry, NetworkConfig clientNetworkConfig, BufferAllocator clientBufferAllocator, - ReadablePacketRegistry clientPacketRegistry) { + ReadableNetworkPacketRegistry clientPacketRegistry) { var asyncClientToServer = new CompletableFuture(); var asyncServerToClient = new CompletableFuture(); - var serverNetwork = NetworkFactory.newDefaultServerNetwork( + var serverNetwork = NetworkFactory.defaultServerNetwork( serverNetworkConfig, serverBufferAllocator, serverPacketRegistry); @@ -190,12 +190,12 @@ protected TestNetwork buildDefaultNetwork( serverNetwork.onAccept(asyncServerToClient::complete); - var clientNetwork = NetworkFactory.newDefaultClientNetwork( + var clientNetwork = NetworkFactory.defaultClientNetwork( clientNetworkConfig, clientBufferAllocator, clientPacketRegistry); clientNetwork - .connect(serverAddress) + .connectAsync(serverAddress) .thenApply(asyncClientToServer::complete); return new TestNetwork<>( diff --git a/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java index cca79717..be347c17 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java @@ -1,33 +1,34 @@ package javasabr.rlib.network; -import static java.util.stream.Collectors.toList; -import static javasabr.rlib.network.NetworkFactory.newDefaultClientNetwork; -import static javasabr.rlib.network.NetworkFactory.newDefaultServerNetwork; import static javasabr.rlib.network.ServerNetworkConfig.DEFAULT_SERVER; +import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.time.Duration; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; import javasabr.rlib.common.util.ObjectUtils; import javasabr.rlib.common.util.StringUtils; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; -import javasabr.rlib.network.annotation.PacketDescription; +import javasabr.rlib.network.annotation.NetworkPacketDescription; import javasabr.rlib.network.impl.DefaultBufferAllocator; import javasabr.rlib.network.impl.DefaultConnection; -import javasabr.rlib.network.packet.impl.DefaultReadablePacket; -import javasabr.rlib.network.packet.impl.DefaultWritablePacket; -import javasabr.rlib.network.packet.registry.ReadablePacketRegistry; +import javasabr.rlib.network.packet.MarkerNetworkPacket; +import javasabr.rlib.network.packet.impl.DefaultReadableNetworkPacket; +import javasabr.rlib.network.packet.impl.DefaultWritableNetworkPacket; +import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; +import javasabr.rlib.network.server.ServerNetwork; +import lombok.CustomLog; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; import lombok.ToString; +import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -36,16 +37,15 @@ * * @author JavaSaBr */ +@CustomLog public class DefaultNetworkTest extends BaseNetworkTest { - private static final Logger LOGGER = LoggerManager.getLogger(DefaultNetworkTest.class); - // client packets interface ClientPackets { @RequiredArgsConstructor - @PacketDescription(id = 1) - class RequestEchoMessage extends DefaultWritablePacket { + @NetworkPacketDescription(id = 1) + class RequestEchoMessage extends DefaultWritableNetworkPacket { private final String message; @@ -56,34 +56,35 @@ protected void writeImpl(ByteBuffer buffer) { } } - @PacketDescription(id = 2) - class RequestServerTime extends DefaultWritablePacket {} + @NetworkPacketDescription(id = 2) + class RequestServerTime extends DefaultWritableNetworkPacket implements MarkerNetworkPacket {} @ToString @RequiredArgsConstructor - @PacketDescription(id = 3) - class ResponseEchoMessage extends DefaultReadablePacket { + @NetworkPacketDescription(id = 3) + class ResponseEchoMessage extends DefaultReadableNetworkPacket { @Getter + @Nullable private volatile String message; @Override - protected void readImpl(DefaultConnection connection, ByteBuffer buffer) { - super.readImpl(connection, buffer); - message = readString(buffer); + protected void readImpl(ByteBuffer buffer) { + message = readString(buffer, Integer.MAX_VALUE); } } @ToString - @PacketDescription(id = 4) - class ResponseServerTime extends DefaultReadablePacket { + @NetworkPacketDescription(id = 4) + class ResponseServerTime extends DefaultReadableNetworkPacket { @Getter + @Nullable private volatile LocalDateTime localDateTime; @Override - protected void readImpl(DefaultConnection connection, ByteBuffer buffer) { - super.readImpl(connection, buffer); + protected void readImpl(ByteBuffer buffer) { + super.readImpl(buffer); localDateTime = LocalDateTime.ofEpochSecond(readLong(buffer), 0, ZoneOffset.ofTotalSeconds(readInt(buffer))); } } @@ -93,43 +94,25 @@ protected void readImpl(DefaultConnection connection, ByteBuffer buffer) { interface ServerPackets { @ToString - @PacketDescription(id = 1) - class RequestEchoMessage extends DefaultReadablePacket { + @NetworkPacketDescription(id = 1) + class RequestEchoMessage extends DefaultReadableNetworkPacket { private volatile String message; @Override - protected void readImpl(DefaultConnection connection, ByteBuffer buffer) { - super.readImpl(connection, buffer); - message = readString(buffer); - } - - @Override - protected void executeImpl(DefaultConnection connection) { - super.executeImpl(connection); - connection.send(new ResponseEchoMessage(message)); + protected void readImpl(ByteBuffer buffer) { + super.readImpl(buffer); + message = readString(buffer, Integer.MAX_VALUE); } } @ToString - @PacketDescription(id = 2) - class RequestServerTime extends DefaultReadablePacket { - - @Override - protected void readImpl(DefaultConnection connection, ByteBuffer buffer) { - super.readImpl(connection, buffer); - } - - @Override - protected void executeImpl(DefaultConnection connection) { - super.executeImpl(connection); - connection.send(new ResponseServerTime()); - } - } + @NetworkPacketDescription(id = 2) + class RequestServerTime extends DefaultReadableNetworkPacket implements MarkerNetworkPacket {} @RequiredArgsConstructor - @PacketDescription(id = 3) - class ResponseEchoMessage extends DefaultWritablePacket { + @NetworkPacketDescription(id = 3) + class ResponseEchoMessage extends DefaultWritableNetworkPacket { private final String message; @@ -140,19 +123,15 @@ protected void writeImpl(ByteBuffer buffer) { } } - @PacketDescription(id = 4) - class ResponseServerTime extends DefaultWritablePacket { + @NetworkPacketDescription(id = 4) + class ResponseServerTime extends DefaultWritableNetworkPacket { @Override protected void writeImpl(ByteBuffer buffer) { super.writeImpl(buffer); var dateTime = ZonedDateTime.now(); writeLong(buffer, dateTime.toEpochSecond()); - writeInt( - buffer, - dateTime - .getOffset() - .getTotalSeconds()); + writeInt(buffer, dateTime.getOffset().getTotalSeconds()); } } } @@ -161,25 +140,37 @@ protected void writeImpl(ByteBuffer buffer) { @SneakyThrows void echoNetworkTest() { - var serverNetwork = newDefaultServerNetwork(ReadablePacketRegistry.of( - DefaultReadablePacket.class, + ReadableNetworkPacketRegistry serverPackets = ReadableNetworkPacketRegistry.of( + DefaultReadableNetworkPacket.class, ServerPackets.RequestEchoMessage.class, - ServerPackets.RequestServerTime.class)); - var serverAddress = serverNetwork.start(); + ServerPackets.RequestServerTime.class); + ReadableNetworkPacketRegistry clientPackets = ReadableNetworkPacketRegistry.of( + DefaultReadableNetworkPacket.class, + ClientPackets.ResponseEchoMessage.class, + ClientPackets.ResponseServerTime.class); + + ServerNetwork serverNetwork = NetworkFactory.defaultServerNetwork(serverPackets); + InetSocketAddress serverAddress = serverNetwork.start(); + var counter = new CountDownLatch(90); serverNetwork .accepted() .flatMap(Connection::receivedEvents) - .doOnNext(event -> event.packet.execute(event.connection)) - .subscribe(event -> LOGGER.info("Received from client: " + event.packet)); - - var clientNetwork = newDefaultClientNetwork(ReadablePacketRegistry.of( - DefaultReadablePacket.class, - ClientPackets.ResponseEchoMessage.class, - ClientPackets.ResponseServerTime.class)); + .doOnNext(event -> { + var connection = event.connection(); + var packet = event.packet(); + if (packet instanceof ServerPackets.RequestEchoMessage request) { + connection.send(new ServerPackets.ResponseEchoMessage(request.message)); + } else if (packet instanceof ServerPackets.RequestServerTime request) { + connection.send(new ServerPackets.ResponseServerTime()); + } + }) + .subscribe(event -> log.info(event, "Received from client:[%s]"::formatted)); + + var clientNetwork = NetworkFactory.defaultClientNetwork(clientPackets); clientNetwork - .connected(serverAddress) + .connectReactive(serverAddress) .doOnNext(connection -> IntStream .range(10, 100) .forEach(length -> { @@ -191,7 +182,7 @@ void echoNetworkTest() { })) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { - LOGGER.info("Received from server: " + event.packet); + log.info(event, "Received from server:[%s]"::formatted); counter.countDown(); }); @@ -206,12 +197,12 @@ void echoNetworkTest() { @Test void shouldNotUseMappedBuffers() { - var serverPacketRegistry = ReadablePacketRegistry.of( - DefaultReadablePacket.class, + var serverPacketRegistry = ReadableNetworkPacketRegistry.of( + DefaultReadableNetworkPacket.class, ServerPackets.RequestEchoMessage.class, ServerPackets.RequestServerTime.class); - var clientPacketRegistry = ReadablePacketRegistry.of( - DefaultReadablePacket.class, + var clientPacketRegistry = ReadableNetworkPacketRegistry.of( + DefaultReadableNetworkPacket.class, ClientPackets.ResponseEchoMessage.class, ClientPackets.ResponseServerTime.class); @@ -233,32 +224,32 @@ public ByteBuffer takeBuffer(int bufferSize) { int packetCount = 200; - try (var testNetwork = buildDefaultNetwork( + try (TestNetwork testNetwork = buildDefaultNetwork( serverAllocator, serverPacketRegistry, clientAllocator, clientPacketRegistry)) { - var bufferSize = testNetwork.serverNetworkConfig.getReadBufferSize() / 3; - + int bufferSize = testNetwork.serverNetworkConfig.readBufferSize() / 3; var random = ThreadLocalRandom.current(); - var clientToServer = testNetwork.clientToServer; - var serverToClient = testNetwork.serverToClient; + DefaultConnection clientToServer = testNetwork.clientToServer; + DefaultConnection serverToClient = testNetwork.serverToClient; var pendingPacketsOnServer = serverToClient .receivedPackets() .buffer(packetCount); - var messages = IntStream + List messages = IntStream .range(0, packetCount) .mapToObj(value -> StringUtils.generate(random.nextInt(0, bufferSize))) .peek(message -> clientToServer.send(new ClientPackets.RequestEchoMessage(message))) - .collect(toList()); + .toList(); - var receivedPackets = ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5))); + List receivedPackets = + ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5))); - Assertions.assertEquals(receivedPackets.size(), packetCount, "Didn't receive all packets"); + Assertions.assertEquals(packetCount, receivedPackets.size(), "Didn't receive all packets"); var wrongPacket = receivedPackets .stream() diff --git a/rlib-network/src/test/java/javasabr/rlib/network/IdBasedReadableNetworkPacketRegistryTest.java b/rlib-network/src/test/java/javasabr/rlib/network/IdBasedReadableNetworkPacketRegistryTest.java new file mode 100644 index 00000000..c30249ee --- /dev/null +++ b/rlib-network/src/test/java/javasabr/rlib/network/IdBasedReadableNetworkPacketRegistryTest.java @@ -0,0 +1,123 @@ +package javasabr.rlib.network; + +import javasabr.rlib.collections.array.Array; +import javasabr.rlib.common.util.ClassUtils; +import javasabr.rlib.network.annotation.NetworkPacketDescription; +import javasabr.rlib.network.impl.DefaultConnection; +import javasabr.rlib.network.packet.IdBasedReadableNetworkPacket; +import javasabr.rlib.network.packet.impl.AbstractIdBasedReadableNetworkPacket; +import javasabr.rlib.network.packet.impl.DefaultReadableNetworkPacket; +import javasabr.rlib.network.packet.registry.impl.IdBasedReadableNetworkPacketRegistry; +import lombok.NoArgsConstructor; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author JavaSaBr + */ +public class IdBasedReadableNetworkPacketRegistryTest { + + @NoArgsConstructor + @NetworkPacketDescription(id = 1) + public static class Impl1 extends DefaultReadableNetworkPacket {} + + @NoArgsConstructor + @NetworkPacketDescription(id = 2) + public static class Impl2 extends DefaultReadableNetworkPacket {} + + @NoArgsConstructor + @NetworkPacketDescription(id = 3) + public static class Impl3 extends DefaultReadableNetworkPacket {} + + @NoArgsConstructor + private static class PrivateBase extends AbstractIdBasedReadableNetworkPacket {} + + @NoArgsConstructor + @NetworkPacketDescription(id = 1) + private static class PrivateImpl1 extends PrivateBase {} + + @NoArgsConstructor + @NetworkPacketDescription(id = 10) + private static class PrivateImpl2 extends PrivateBase {} + + @NoArgsConstructor + public static class PublicBase extends AbstractIdBasedReadableNetworkPacket {} + + @NoArgsConstructor + @NetworkPacketDescription(id = 1) + public static class PublicImpl1 extends PublicBase {} + + @NoArgsConstructor + @NetworkPacketDescription(id = 5) + public static class PublicImpl2 extends PublicBase {} + + @Test + void shouldBeCreated() { + Assertions.assertDoesNotThrow( + () -> new IdBasedReadableNetworkPacketRegistry<>(IdBasedReadableNetworkPacket.class)); + } + + @Test + void shouldRegister3PacketsByArray() { + + var registry = new IdBasedReadableNetworkPacketRegistry<>(IdBasedReadableNetworkPacket.class) + .register(Array.typed(Class.class, Impl1.class, Impl2.class, Impl3.class)); + + Assertions.assertInstanceOf(Impl1.class, registry.resolvePrototypeById(1)); + Assertions.assertInstanceOf(Impl2.class, registry.resolvePrototypeById(2)); + Assertions.assertInstanceOf(Impl3.class, registry.resolvePrototypeById(3)); + } + + @Test + void shouldRegister3PacketsByVarargs() { + + var registry = new IdBasedReadableNetworkPacketRegistry<>(IdBasedReadableNetworkPacket.class) + .register(Impl1.class, Impl2.class, Impl3.class); + + Assertions.assertInstanceOf(Impl1.class, registry.resolvePrototypeById(1)); + Assertions.assertInstanceOf(Impl2.class, registry.resolvePrototypeById(2)); + Assertions.assertInstanceOf(Impl3.class, registry.resolvePrototypeById(3)); + } + + @Test + void shouldRegister3PacketsBySingle() { + + var registry = new IdBasedReadableNetworkPacketRegistry<>(IdBasedReadableNetworkPacket.class) + .register(Impl1.class) + .register(Impl2.class) + .register(Impl3.class); + + Assertions.assertInstanceOf(Impl1.class, registry.resolvePrototypeById(1)); + Assertions.assertInstanceOf(Impl2.class, registry.resolvePrototypeById(2)); + Assertions.assertInstanceOf(Impl3.class, registry.resolvePrototypeById(3)); + } + + @Test + void shouldRegister2PrivatePacketsBySingle() { + + var registry = new IdBasedReadableNetworkPacketRegistry<>(PrivateBase.class) + .register(PrivateImpl1.class, PrivateImpl1::new) + .register(PrivateImpl2.class, PrivateImpl2::new); + + Assertions.assertInstanceOf(PrivateImpl1.class, registry.resolvePrototypeById(1)); + Assertions.assertInstanceOf(PrivateImpl2.class, registry.resolvePrototypeById(10)); + } + + @Test + void shouldNotAcceptWrongTypes() { + + var array = Array.typed( + Class.class, + PrivateImpl1.class, + PrivateImpl2.class, + PublicImpl1.class, + PublicImpl2.class); + + var registry = new IdBasedReadableNetworkPacketRegistry<>(PublicBase.class) + .register(ClassUtils.>>unsafeNNCast(array)); + + Assertions.assertInstanceOf(PublicImpl1.class, registry.resolvePrototypeById(1)); + Assertions.assertThrows(IllegalArgumentException.class, () -> registry.resolvePrototypeById(2)); + Assertions.assertInstanceOf(PublicImpl2.class, registry.resolvePrototypeById(5)); + } +} diff --git a/rlib-network/src/test/java/javasabr/rlib/network/IdBasedReadablePacketRegistryTest.java b/rlib-network/src/test/java/javasabr/rlib/network/IdBasedReadablePacketRegistryTest.java deleted file mode 100644 index dbfbd352..00000000 --- a/rlib-network/src/test/java/javasabr/rlib/network/IdBasedReadablePacketRegistryTest.java +++ /dev/null @@ -1,122 +0,0 @@ -package javasabr.rlib.network; - -import javasabr.rlib.collections.array.Array; -import javasabr.rlib.common.util.ClassUtils; -import javasabr.rlib.network.annotation.PacketDescription; -import javasabr.rlib.network.impl.DefaultConnection; -import javasabr.rlib.network.packet.IdBasedReadablePacket; -import javasabr.rlib.network.packet.impl.AbstractIdBasedReadablePacket; -import javasabr.rlib.network.packet.impl.DefaultReadablePacket; -import javasabr.rlib.network.packet.registry.impl.IdBasedReadablePacketRegistry; -import lombok.NoArgsConstructor; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -/** - * @author JavaSaBr - */ -public class IdBasedReadablePacketRegistryTest { - - @NoArgsConstructor - @PacketDescription(id = 1) - public static class Impl1 extends DefaultReadablePacket {} - - @NoArgsConstructor - @PacketDescription(id = 2) - public static class Impl2 extends DefaultReadablePacket {} - - @NoArgsConstructor - @PacketDescription(id = 3) - public static class Impl3 extends DefaultReadablePacket {} - - @NoArgsConstructor - private static class PrivateBase extends AbstractIdBasedReadablePacket {} - - @NoArgsConstructor - @PacketDescription(id = 1) - private static class PrivateImpl1 extends PrivateBase {} - - @NoArgsConstructor - @PacketDescription(id = 10) - private static class PrivateImpl2 extends PrivateBase {} - - @NoArgsConstructor - public static class PublicBase extends AbstractIdBasedReadablePacket {} - - @NoArgsConstructor - @PacketDescription(id = 1) - public static class PublicImpl1 extends PublicBase {} - - @NoArgsConstructor - @PacketDescription(id = 5) - public static class PublicImpl2 extends PublicBase {} - - @Test - Object shouldBeCreated() { - return new IdBasedReadablePacketRegistry<>(IdBasedReadablePacket.class); - } - - @Test - void shouldRegister3PacketsByArray() { - - var registry = new IdBasedReadablePacketRegistry<>(IdBasedReadablePacket.class).register(Array.typed( - Class.class, - Impl1.class, - Impl2.class, - Impl3.class)); - - Assertions.assertTrue(registry.findById(1) instanceof Impl1); - Assertions.assertTrue(registry.findById(2) instanceof Impl2); - Assertions.assertTrue(registry.findById(3) instanceof Impl3); - } - - @Test - void shouldRegister3PacketsByVarargs() { - - var registry = new IdBasedReadablePacketRegistry<>(IdBasedReadablePacket.class).register( - Impl1.class, - Impl2.class, - Impl3.class); - - Assertions.assertTrue(registry.findById(1) instanceof Impl1); - Assertions.assertTrue(registry.findById(2) instanceof Impl2); - Assertions.assertTrue(registry.findById(3) instanceof Impl3); - } - - @Test - void shouldRegister3PacketsBySingle() { - - var registry = new IdBasedReadablePacketRegistry<>(IdBasedReadablePacket.class) - .register(Impl1.class) - .register(Impl2.class) - .register(Impl3.class); - - Assertions.assertTrue(registry.findById(1) instanceof Impl1); - Assertions.assertTrue(registry.findById(2) instanceof Impl2); - Assertions.assertTrue(registry.findById(3) instanceof Impl3); - } - - @Test - void shouldRegister2PrivatePacketsBySingle() { - - var registry = new IdBasedReadablePacketRegistry<>(PrivateBase.class) - .register(PrivateImpl1.class, PrivateImpl1::new) - .register(PrivateImpl2.class, PrivateImpl2::new); - - Assertions.assertTrue(registry.findById(1) instanceof PrivateImpl1); - Assertions.assertTrue(registry.findById(10) instanceof PrivateImpl2); - } - - @Test - void shouldNotAcceptWrongTypes() { - - var array = Array.typed(Class.class, PrivateImpl1.class, PrivateImpl2.class, PublicImpl1.class, PublicImpl2.class); - - var registry = new IdBasedReadablePacketRegistry<>(PublicBase.class) - .register(ClassUtils.>>unsafeNNCast(array)); - - Assertions.assertTrue(registry.findById(1) instanceof PublicImpl1); - Assertions.assertThrows(IllegalArgumentException.class, () -> registry.findById(2)); - Assertions.assertTrue(registry.findById(5) instanceof PublicImpl2); - } -} diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java index eb02065f..c78b7177 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java @@ -1,12 +1,12 @@ package javasabr.rlib.network; import static java.util.stream.Collectors.toList; -import static javasabr.rlib.network.NetworkFactory.newStringDataClientNetwork; -import static javasabr.rlib.network.NetworkFactory.newStringDataServerNetwork; import static javasabr.rlib.network.ServerNetworkConfig.DEFAULT_SERVER; +import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.time.Duration; +import java.util.List; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; @@ -16,12 +16,14 @@ import java.util.stream.IntStream; import javasabr.rlib.common.util.ObjectUtils; import javasabr.rlib.common.util.StringUtils; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.ServerNetworkConfig.SimpleServerNetworkConfig; import javasabr.rlib.network.client.ClientNetwork; import javasabr.rlib.network.impl.DefaultBufferAllocator; -import javasabr.rlib.network.packet.impl.StringWritablePacket; +import javasabr.rlib.network.impl.StringDataConnection; +import javasabr.rlib.network.packet.impl.StringReadablePacket; +import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; +import javasabr.rlib.network.server.ServerNetwork; +import lombok.CustomLog; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -32,36 +34,36 @@ * * @author JavaSaBr */ +@CustomLog public class StringNetworkTest extends BaseNetworkTest { - private static final Logger LOGGER = LoggerManager.getLogger(StringNetworkTest.class); - @Test @SneakyThrows void echoNetworkTest() { - var serverNetwork = newStringDataServerNetwork(); - var serverAddress = serverNetwork.start(); + ServerNetwork serverNetwork = NetworkFactory.stringDataServerNetwork(); + InetSocketAddress serverAddress = serverNetwork.start(); + var counter = new CountDownLatch(90); serverNetwork .accepted() .flatMap(Connection::receivedEvents) .subscribe(event -> { - var message = event.packet.getData(); - LOGGER.info("Received from client: " + message); - event.connection.send(new StringWritablePacket("Echo: " + message)); + String message = event.packet().getData(); + log.info(message, "Received from client:[%s]"::formatted); + event.connection().send(new StringWritableNetworkPacket("Echo: " + message)); }); - var clientNetwork = newStringDataClientNetwork(); + var clientNetwork = NetworkFactory.stringDataClientNetwork(); clientNetwork - .connected(serverAddress) + .connectReactive(serverAddress) .doOnNext(connection -> IntStream .range(10, 100) - .forEach(length -> connection.send(new StringWritablePacket(StringUtils.generate(length))))) + .forEach(length -> connection.send(new StringWritableNetworkPacket(StringUtils.generate(length))))) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { - LOGGER.info("Received from server: " + event.packet.getData()); + log.info(event.packet().getData(), "Received from server:[%s]"::formatted); counter.countDown(); }); @@ -94,33 +96,32 @@ public ByteBuffer takeBuffer(int bufferSize) { int packetCount = 200; - try (var testNetwork = buildStringNetwork(serverAllocator, clientAllocator)) { - - var bufferSize = testNetwork.serverNetworkConfig.getReadBufferSize() / 3; - + try (TestNetwork testNetwork = buildStringNetwork(serverAllocator, clientAllocator)) { + int bufferSize = testNetwork.serverNetworkConfig.readBufferSize() / 3; var random = ThreadLocalRandom.current(); - var clientToServer = testNetwork.clientToServer; - var serverToClient = testNetwork.serverToClient; + StringDataConnection clientToServer = testNetwork.clientToServer; + StringDataConnection serverToClient = testNetwork.serverToClient; var pendingPacketsOnServer = serverToClient .receivedPackets() .buffer(packetCount); - var messages = IntStream + List messages = IntStream .range(0, packetCount) .mapToObj(value -> StringUtils.generate(random.nextInt(0, bufferSize))) .peek(message -> { - LOGGER.info("Send " + message.length() + " symbols to server"); - clientToServer.send(new StringWritablePacket(message)); + log.info(message.length(), "Send [%s] symbols to server"::formatted); + clientToServer.send(new StringWritableNetworkPacket(message)); }) - .collect(toList()); + .toList(); - var receivedPackets = ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5))); + List receivedPackets = ObjectUtils + .notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5))); - LOGGER.info("Received " + receivedPackets.size() + " packets from client"); + log.info(receivedPackets.size(), "Received [%s] packets from client"::formatted); - Assertions.assertEquals(receivedPackets.size(), packetCount, "Didn't receive all packets"); + Assertions.assertEquals(packetCount, receivedPackets.size(), "Didn't receive all packets"); var wrongPacket = receivedPackets .stream() @@ -136,17 +137,13 @@ public ByteBuffer takeBuffer(int bufferSize) { @Test void shouldReceiveManyPacketsFromSmallToBigSize() { - int packetCount = 200; - - try (var testNetwork = buildStringNetwork()) { - - var bufferSize = testNetwork.serverNetworkConfig.getReadBufferSize(); - + try (TestNetwork testNetwork = buildStringNetwork()) { + int bufferSize = testNetwork.serverNetworkConfig.readBufferSize(); var random = ThreadLocalRandom.current(); - var clientToServer = testNetwork.clientToServer; - var serverToClient = testNetwork.serverToClient; + StringDataConnection clientToServer = testNetwork.clientToServer; + StringDataConnection serverToClient = testNetwork.serverToClient; var pendingPacketsOnServer = serverToClient .receivedPackets() @@ -159,16 +156,17 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { return StringUtils.generate(length); }) .peek(message -> { - LOGGER.info("Send " + message.length() + " symbols to server"); - clientToServer.send(new StringWritablePacket(message)); + log.info(message.length(), "Send [%s] symbols to server"::formatted); + clientToServer.send(new StringWritableNetworkPacket(message)); }) - .collect(toList()); + .toList(); - var receivedPackets = ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5))); + List receivedPackets = + ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5))); - LOGGER.info("Received " + receivedPackets.size() + " packets from client"); + log.info(receivedPackets.size(), "Received [%s] packets from client"::formatted); - Assertions.assertEquals(receivedPackets.size(), packetCount, "Didn't receive all packets"); + Assertions.assertEquals(packetCount, receivedPackets.size(), "Didn't receive all packets"); var wrongPacket = receivedPackets .stream() @@ -187,20 +185,18 @@ void shouldSendBiggerPacketThanWriteBuffer() { int packetCount = 10_000; - try (var testNetwork = buildStringNetwork()) { - - var bufferSize = testNetwork.clientNetworkConfig.getWriteBufferSize(); - + try (TestNetwork testNetwork = buildStringNetwork()) { + int bufferSize = testNetwork.clientNetworkConfig.writeBufferSize(); var random = ThreadLocalRandom.current(); - var clientToServer = testNetwork.clientToServer; - var serverToClient = testNetwork.serverToClient; + StringDataConnection clientToServer = testNetwork.clientToServer; + StringDataConnection serverToClient = testNetwork.serverToClient; var pendingPacketsOnServer = serverToClient .receivedPackets() .buffer(packetCount); - var messages = IntStream + List messages = IntStream .range(0, packetCount) .mapToObj(value -> { @@ -209,16 +205,17 @@ void shouldSendBiggerPacketThanWriteBuffer() { return StringUtils.generate(length); }) .peek(message -> { - LOGGER.info("Send " + message.length() + " symbols to server"); - clientToServer.send(new StringWritablePacket(message)); + log.info(message.length(), "Send [%s] symbols to server"::formatted); + clientToServer.send(new StringWritableNetworkPacket(message)); }) - .collect(toList()); + .toList(); - var receivedPackets = ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5))); + List receivedPackets = + ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5))); - LOGGER.info("Received " + receivedPackets.size() + " packets from client"); + log.info(receivedPackets.size(), "Received [%s] packets from client"::formatted); - Assertions.assertEquals(receivedPackets.size(), packetCount, "Didn't receive all packets"); + Assertions.assertEquals(packetCount, receivedPackets.size(), "Didn't receive all packets"); var wrongPacket = receivedPackets .stream() @@ -246,30 +243,31 @@ void testServerWithMultiplyClients() { var serverAllocator = new DefaultBufferAllocator(serverConfig); var clientAllocator = new DefaultBufferAllocator(NetworkConfig.DEFAULT_CLIENT); - var clientCount = 100; - var packetsPerClient = 100; + int clientCount = 100; + int packetsPerClient = 100; + int minMessageLength = 10; + int maxMessageLength = (int) (DEFAULT_SERVER.readBufferSize() * 1.5); + var counter = new CountDownLatch(clientCount * packetsPerClient); - var minMessageLength = 10; - var maxMessageLength = (int) (DEFAULT_SERVER.getReadBufferSize() * 1.5); var sentPacketsToServer = new AtomicInteger(); var receivedPacketsOnServer = new AtomicInteger(); var receivedPacketsOnClients = new AtomicInteger(); - var serverNetwork = newStringDataServerNetwork(serverConfig, serverAllocator); - var serverAddress = serverNetwork.start(); + ServerNetwork serverNetwork = NetworkFactory.stringDataServerNetwork(serverConfig, serverAllocator); + InetSocketAddress serverAddress = serverNetwork.start(); serverNetwork .accepted() .flatMap(Connection::receivedEvents) .doOnNext(event -> receivedPacketsOnServer.incrementAndGet()) - .subscribe(event -> event.connection.send(newMessage(minMessageLength, maxMessageLength))); + .subscribe(event -> event.connection().send(newMessage(minMessageLength, maxMessageLength))); Flux .fromStream(IntStream .range(0, clientCount) - .mapToObj(value -> newStringDataClientNetwork(NetworkConfig.DEFAULT_CLIENT, clientAllocator))) + .mapToObj(value -> NetworkFactory.stringDataClientNetwork(NetworkConfig.DEFAULT_CLIENT, clientAllocator))) .doOnDiscard(ClientNetwork.class, Network::shutdown) - .flatMap(client -> client.connected(serverAddress)) + .flatMap(client -> client.connectReactive(serverAddress)) .flatMap(connection -> { var receivedEvents = connection.receivedEvents(); @@ -299,17 +297,19 @@ void testServerWithMultiplyClients() { @SneakyThrows void testServerWithMultiplyClientsUsingOldApi() { - var serverNetwork = newStringDataServerNetwork(SimpleServerNetworkConfig + var serverNetwork = NetworkFactory.stringDataServerNetwork(SimpleServerNetworkConfig .builder() .threadGroupSize(10) .build()); - var serverAddress = serverNetwork.start(); - var clientCount = 100; - var packetsPerClient = 1000; + InetSocketAddress serverAddress = serverNetwork.start(); + + int clientCount = 100; + int packetsPerClient = 1000; + int minMessageLength = 10; + int maxMessageLength = (int) (DEFAULT_SERVER.readBufferSize() * 1.5); + var counter = new CountDownLatch(clientCount * packetsPerClient); - var minMessageLength = 10; - var maxMessageLength = (int) (DEFAULT_SERVER.getReadBufferSize() * 1.5); var sentPacketsToServer = new AtomicInteger(); var receivedPacketsOnServer = new AtomicInteger(); var receivedPacketsOnClients = new AtomicInteger(); @@ -323,17 +323,17 @@ void testServerWithMultiplyClientsUsingOldApi() { connectedClients.countDown(); }); - var clients = IntStream + List> clients = IntStream .range(0, clientCount) - .mapToObj(value -> newStringDataClientNetwork()) + .mapToObj(value -> NetworkFactory.stringDataClientNetwork()) .peek(client -> client.connect(serverAddress)) - .collect(toList()); + .toList(); connectedClients.await(); clients .stream() - .map(ClientNetwork::getCurrentConnection) + .map(ClientNetwork::currentConnection) .filter(Objects::nonNull) .peek(connection -> connection.onReceive((con, packet) -> { receivedPacketsOnClients.incrementAndGet(); @@ -359,24 +359,22 @@ void shouldGetAllPacketWithFeedback() { int packetCount = 200; - try (var testNetwork = buildStringNetwork()) { - - var bufferSize = testNetwork.serverNetworkConfig.getReadBufferSize() / 3; - + try (TestNetwork testNetwork = buildStringNetwork()) { + int bufferSize = testNetwork.serverNetworkConfig.readBufferSize() / 3; var random = ThreadLocalRandom.current(); - var clientToServer = testNetwork.clientToServer; - var serverToClient = testNetwork.serverToClient; + StringDataConnection clientToServer = testNetwork.clientToServer; + StringDataConnection serverToClient = testNetwork.serverToClient; var pendingPacketsOnServer = serverToClient .receivedPackets() .buffer(packetCount); - var asyncResults = IntStream + List> asyncResults = IntStream .range(0, packetCount) .mapToObj(value -> StringUtils.generate(random.nextInt(0, bufferSize))) - .map(message -> clientToServer.sendWithFeedback(new StringWritablePacket(message))) - .collect(toList()); + .map(message -> clientToServer.sendWithFeedback(new StringWritableNetworkPacket(message))) + .toList(); CompletableFuture .allOf(asyncResults.toArray(CompletableFuture[]::new)) @@ -394,11 +392,11 @@ void shouldGetAllPacketWithFeedback() { // so all packets are already sent, we should not wait for long time to get result var receivedPackets = ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofMillis(100))); - Assertions.assertEquals(receivedPackets.size(), packetCount, "Didn't receive all packets"); + Assertions.assertEquals(packetCount, receivedPackets.size(), "Didn't receive all packets"); } } - private static StringWritablePacket newMessage(int minMessageLength, int maxMessageLength) { - return new StringWritablePacket(StringUtils.generate(minMessageLength, maxMessageLength)); + private static StringWritableNetworkPacket newMessage(int minMessageLength, int maxMessageLength) { + return new StringWritableNetworkPacket(StringUtils.generate(minMessageLength, maxMessageLength)); } } diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java index aace14f0..4fcbc359 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java @@ -20,10 +20,10 @@ import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.impl.DefaultBufferAllocator; -import javasabr.rlib.network.packet.impl.AbstractSSLPacketReader; -import javasabr.rlib.network.packet.impl.AbstractSSLPacketWriter; +import javasabr.rlib.network.packet.impl.AbstractSslNetworkPacketReader; +import javasabr.rlib.network.packet.impl.AbstractSslNetworkPacketWriter; import javasabr.rlib.network.packet.impl.StringReadablePacket; -import javasabr.rlib.network.packet.impl.StringWritablePacket; +import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; import javasabr.rlib.network.util.NetworkUtils; import javax.net.ssl.SSLSocket; import lombok.SneakyThrows; @@ -89,7 +89,7 @@ void serverSSLNetworkTest() { .subscribe(event -> { var message = event.packet.getData(); LOGGER.info("Received from client: " + message); - event.connection.send(new StringWritablePacket("Echo: " + message)); + event.connection.send(new StringWritableNetworkPacket("Echo: " + message)); }); var clientSslContext = NetworkUtils.createAllTrustedClientSslContext(); @@ -99,7 +99,7 @@ void serverSSLNetworkTest() { var buffer = ByteBuffer.allocate(1024); buffer.position(2); - new StringWritablePacket("Hello SSL").write(buffer); + new StringWritableNetworkPacket("Hello SSL").write(buffer); buffer.putShort(0, (short) buffer.position()); buffer.flip(); @@ -151,7 +151,7 @@ void clientSSLNetworkTest() { clientNetwork .connected(new InetSocketAddress("localhost", serverPort)) - .doOnNext(connection -> connection.send(new StringWritablePacket("Hello SSL"))) + .doOnNext(connection -> connection.send(new StringWritableNetworkPacket("Hello SSL"))) .doOnError(Throwable::printStackTrace) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { @@ -182,7 +182,7 @@ void clientSSLNetworkTest() { buffer.clear(); buffer.position(2); - new StringWritablePacket("Echo: Hello SSL").write(buffer); + new StringWritableNetworkPacket("Echo: Hello SSL").write(buffer); buffer.putShort(0, (short) buffer.position()); buffer.flip(); @@ -228,7 +228,7 @@ void echoNetworkTest() { .subscribe(event -> { var message = event.packet.getData(); LOGGER.info("Received from client: " + message); - event.connection.send(new StringWritablePacket("Echo: " + message)); + event.connection.send(new StringWritableNetworkPacket("Echo: " + message)); }); var clientSslContext = NetworkUtils.createAllTrustedClientSslContext(); @@ -267,8 +267,8 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { //System.setProperty("javax.net.debug", "all"); //LoggerManager.enable(AbstractPacketReader.class, LoggerLevel.DEBUG); //LoggerManager.enable(AbstractPacketWriter.class, LoggerLevel.DEBUG); - LoggerManager.enable(AbstractSSLPacketWriter.class, LoggerLevel.DEBUG); - LoggerManager.enable(AbstractSSLPacketReader.class, LoggerLevel.DEBUG); + LoggerManager.enable(AbstractSslNetworkPacketWriter.class, LoggerLevel.DEBUG); + LoggerManager.enable(AbstractSslNetworkPacketReader.class, LoggerLevel.DEBUG); var keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); var serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); @@ -296,7 +296,7 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { var length = value % 3 == 0 ? bufferSize : random.nextInt(0, bufferSize / 2 - 1); return StringUtils.generate(length); }) - .peek(message -> clientToServer.send(new StringWritablePacket(message))) + .peek(message -> clientToServer.send(new StringWritableNetworkPacket(message))) .collect(toList()); var receivedPackets = ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5000))); @@ -315,7 +315,7 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { } } - private static StringWritablePacket newMessage(int minMessageLength, int maxMessageLength) { - return new StringWritablePacket(StringUtils.generate(minMessageLength, maxMessageLength)); + private static StringWritableNetworkPacket newMessage(int minMessageLength, int maxMessageLength) { + return new StringWritableNetworkPacket(StringUtils.generate(minMessageLength, maxMessageLength)); } } diff --git a/rlib-network/src/test/java/javasabr/rlib/network/package-info.java b/rlib-network/src/test/java/javasabr/rlib/network/package-info.java new file mode 100644 index 00000000..53222c6a --- /dev/null +++ b/rlib-network/src/test/java/javasabr/rlib/network/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.network; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file From 8c3fca54ecf280ee95bf84bc1cf95384b7960a37 Mon Sep 17 00:00:00 2001 From: javasabr Date: Wed, 1 Oct 2025 20:10:18 +0200 Subject: [PATCH 03/15] redesign network api --- .../rlib/functions/ObjBoolConsumer.java | 10 ++ .../javasabr/rlib/network/NetworkFactory.java | 10 +- .../rlib/network/impl/AbstractConnection.java | 91 +++++------ ...ection.java => AbstractSslConnection.java} | 13 +- .../network/impl/DefaultBufferAllocator.java | 47 +++--- .../network/impl/DefaultDataConnection.java | 18 ++- ...ion.java => DefaultDataSslConnection.java} | 21 +-- .../network/impl/IdBasedPacketConnection.java | 22 +-- .../network/impl/ReuseBufferAllocator.java | 32 ++-- ...tion.java => StringDataSslConnection.java} | 5 +- .../network/packet/NetworkPacketWriter.java | 5 +- .../impl/AbstractNetworkPacketReader.java | 2 - .../impl/AbstractNetworkPacketWriter.java | 81 +++++----- .../impl/AbstractSslNetworkPacketWriter.java | 16 +- .../impl/DefaultNetworkPacketReader.java | 2 - .../impl/DefaultNetworkPacketWriter.java | 20 +-- .../impl/DefaultSslNetworkPacketReader.java | 26 +-- .../impl/DefaultSslNetworkPacketWriter.java | 28 ++-- .../impl/IdBasedNetworkPacketWriter.java | 27 ++-- .../packet/impl/IdBasedPacketReader.java | 20 +-- .../packet/impl/StringReadablePacket.java | 25 +-- .../rlib/network/BaseNetworkTest.java | 10 +- .../rlib/network/StringNetworkTest.java | 11 +- .../rlib/network/StringSSLNetworkTest.java | 149 +++++++++--------- 24 files changed, 365 insertions(+), 326 deletions(-) create mode 100644 rlib-functions/src/main/java/javasabr/rlib/functions/ObjBoolConsumer.java rename rlib-network/src/main/java/javasabr/rlib/network/impl/{AbstractSSLConnection.java => AbstractSslConnection.java} (74%) rename rlib-network/src/main/java/javasabr/rlib/network/impl/{DefaultDataSSLConnection.java => DefaultDataSslConnection.java} (78%) rename rlib-network/src/main/java/javasabr/rlib/network/impl/{StringDataSSLConnection.java => StringDataSslConnection.java} (83%) diff --git a/rlib-functions/src/main/java/javasabr/rlib/functions/ObjBoolConsumer.java b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjBoolConsumer.java new file mode 100644 index 00000000..10f58c68 --- /dev/null +++ b/rlib-functions/src/main/java/javasabr/rlib/functions/ObjBoolConsumer.java @@ -0,0 +1,10 @@ +package javasabr.rlib.functions; + +/** + * @author JavaSaBr + */ +@FunctionalInterface +public interface ObjBoolConsumer { + + void accept(A arg1, boolean arg2); +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/NetworkFactory.java b/rlib-network/src/main/java/javasabr/rlib/network/NetworkFactory.java index 9d680070..5d27f4b8 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/NetworkFactory.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/NetworkFactory.java @@ -7,7 +7,7 @@ import javasabr.rlib.network.impl.DefaultBufferAllocator; import javasabr.rlib.network.impl.DefaultConnection; import javasabr.rlib.network.impl.StringDataConnection; -import javasabr.rlib.network.impl.StringDataSSLConnection; +import javasabr.rlib.network.impl.StringDataSslConnection; import javasabr.rlib.network.packet.impl.DefaultReadableNetworkPacket; import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; import javasabr.rlib.network.server.ServerNetwork; @@ -88,13 +88,13 @@ public static ClientNetwork defaultClientNetwork( * Create string packet based asynchronous secure client network. * */ - public static ClientNetwork stringDataSslClientNetwork( + public static ClientNetwork stringDataSslClientNetwork( NetworkConfig networkConfig, BufferAllocator bufferAllocator, SSLContext sslContext) { return clientNetwork( networkConfig, - (network, channel) -> new StringDataSSLConnection(network, channel, bufferAllocator, sslContext, true)); + (network, channel) -> new StringDataSslConnection(network, channel, bufferAllocator, sslContext, true)); } /** @@ -126,13 +126,13 @@ public static ServerNetwork stringDataServerNetwork( /** * Create string packet based asynchronous secure server network. */ - public static ServerNetwork stringDataSslServerNetwork( + public static ServerNetwork stringDataSslServerNetwork( ServerNetworkConfig networkConfig, BufferAllocator bufferAllocator, SSLContext sslContext) { return serverNetwork( networkConfig, - (network, channel) -> new StringDataSSLConnection(network, channel, bufferAllocator, sslContext, false)); + (network, channel) -> new StringDataSslConnection(network, channel, bufferAllocator, sslContext, false)); } /** diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java index de2764e5..1e32fbbc 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java @@ -12,8 +12,6 @@ import javasabr.rlib.collections.array.ArrayFactory; import javasabr.rlib.collections.array.MutableArray; import javasabr.rlib.collections.deque.DequeFactory; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.Network; @@ -24,7 +22,11 @@ import javasabr.rlib.network.packet.WritableNetworkPacket; import javasabr.rlib.network.packet.impl.WritablePacketWrapper; import javasabr.rlib.network.util.NetworkUtils; +import lombok.AccessLevel; +import lombok.CustomLog; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; import reactor.core.publisher.Flux; import reactor.core.publisher.FluxSink; @@ -34,11 +36,12 @@ * * @author JavaSaBr */ +@CustomLog +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) public abstract class AbstractConnection implements UnsafeConnection { - private static final Logger LOGGER = LoggerManager.getLogger(AbstractConnection.class); - private static class WritablePacketWithFeedback extends WritablePacketWrapper, W> { @@ -47,23 +50,24 @@ public WritablePacketWithFeedback(CompletableFuture attachment, W packe } } - protected final @Getter - String remoteAddress; + @Getter + final String remoteAddress; - protected final Network> network; - protected final BufferAllocator bufferAllocator; - protected final AsynchronousSocketChannel channel; - protected final Deque pendingPackets; - protected final StampedLock lock; + final Network> network; + final BufferAllocator bufferAllocator; + final AsynchronousSocketChannel channel; + final Deque pendingPackets; + final StampedLock lock; - protected final AtomicBoolean isWriting; - protected final AtomicBoolean closed; + final AtomicBoolean isWriting; + final AtomicBoolean closed; - protected final MutableArray, ? super R>> subscribers; + final MutableArray, ? super R>> subscribers; - protected final int maxPacketsByRead; + final int maxPacketsByRead; - protected volatile @Getter long lastActivity; + @Getter + volatile long lastActivity; public AbstractConnection( Network> network, @@ -74,7 +78,7 @@ public AbstractConnection( this.maxPacketsByRead = maxPacketsByRead; this.lock = new StampedLock(); this.channel = channel; - this.pendingPackets = DequeFactory.linkedListBased(); + this.pendingPackets = DequeFactory.arrayBasedBased(WritableNetworkPacket.class); this.network = network; this.isWriting = new AtomicBoolean(false); this.closed = new AtomicBoolean(false); @@ -83,28 +87,16 @@ public AbstractConnection( } @Override - public void onConnected() { - } - - protected abstract NetworkPacketReader getPacketReader(); + public void onConnected() {} - protected abstract NetworkPacketWriter getPacketWriter(); - - protected void handleReceivedPacket(R packet) { - LOGGER.debug( - channel, - packet, - (ch, pck) -> "Handle received packet: %s from: %s".formatted(pck, NetworkUtils.getRemoteAddress(ch))); + protected abstract NetworkPacketReader packetReader(); - subscribers - .iterations() - .forEach(this, packet, BiConsumer::accept); - } + protected abstract NetworkPacketWriter packetWriter(); @Override public void onReceive(BiConsumer, ? super R> consumer) { subscribers.add(consumer); - getPacketReader().startRead(); + packetReader().startRead(); } @Override @@ -130,15 +122,13 @@ protected void registerFluxOnReceivedEvents( } protected void registerFluxOnReceivedPackets(FluxSink sink) { - BiConsumer, R> listener = (connection, packet) -> sink.next(packet); - onReceive(listener); - sink.onDispose(() -> subscribers.remove(listener)); } - protected @Nullable WritableNetworkPacket nextPacketToWrite() { + @Nullable + protected WritableNetworkPacket nextPacketToWrite() { long stamp = lock.writeLock(); try { return pendingPackets.poll(); @@ -158,15 +148,12 @@ public void close() { * Does the process of closing this connection. */ protected void doClose() { - if (channel.isOpen()) { unchecked(channel, AsynchronousChannel::close); } - clearWaitPackets(); - - getPacketReader().close(); - getPacketWriter().close(); + packetReader().close(); + packetWriter().close(); } /** @@ -177,14 +164,20 @@ protected void updateLastActivity() { } @Override - public boolean isClosed() { + public boolean closed() { return closed.get(); } - protected void onWrittenPacket(WritableNetworkPacket packet) { + protected void serializedPacket(WritableNetworkPacket packet) {} + + protected void handleReceivedPacket(R packet) { + log.debug(packet, remoteAddress, "Handle received packet:[%s] from:[%s]"::formatted); + subscribers + .iterations() + .forEach(this, packet, BiConsumer::accept); } - protected void onSentPacket(WritableNetworkPacket packet, Boolean result) { + protected void handleSentPacket(WritableNetworkPacket packet, Boolean result) { if (packet instanceof WritablePacketWithFeedback) { ((WritablePacketWithFeedback) packet) .getAttachment() @@ -199,7 +192,7 @@ public final void send(W packet) { protected void sendImpl(WritableNetworkPacket packet) { - if (isClosed()) { + if (closed()) { return; } @@ -210,7 +203,7 @@ protected void sendImpl(WritableNetworkPacket packet) { lock.unlockWrite(stamp); } - getPacketWriter().writeNextPacket(); + packetWriter().tryToSendNextPacket(); } protected void queueAtFirst(WritableNetworkPacket packet) { @@ -229,7 +222,7 @@ public CompletableFuture sendWithFeedback(W packet) { sendImpl(new WritablePacketWithFeedback<>(asyncResult, packet)); - if (isClosed()) { + if (closed()) { return CompletableFuture.completedFuture(Boolean.FALSE); } @@ -251,7 +244,7 @@ protected void clearWaitPackets() { protected void doClearWaitPackets() { for (var pendingPacket : pendingPackets) { - onSentPacket(pendingPacket, Boolean.FALSE); + handleSentPacket(pendingPacket, Boolean.FALSE); } pendingPackets.clear(); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSSLConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSslConnection.java similarity index 74% rename from rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSSLConnection.java rename to rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSslConnection.java index 31bcc1aa..d88aab8b 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSSLConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractSslConnection.java @@ -9,13 +9,16 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; -public abstract class AbstractSSLConnection extends - AbstractConnection { +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class AbstractSslConnection + extends AbstractConnection { - protected final SSLEngine sslEngine; + final SSLEngine sslEngine; - public AbstractSSLConnection( + public AbstractSslConnection( Network> network, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, @@ -35,6 +38,6 @@ public AbstractSSLConnection( @Override protected void sendImpl(WritableNetworkPacket packet) { super.sendImpl(packet); - getPacketReader().startRead(); + packetReader().startRead(); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultBufferAllocator.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultBufferAllocator.java index 4ffbc7d6..a23fe361 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultBufferAllocator.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultBufferAllocator.java @@ -1,13 +1,14 @@ package javasabr.rlib.network.impl; import java.nio.ByteBuffer; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.NetworkConfig; import javasabr.rlib.reusable.pool.Pool; import javasabr.rlib.reusable.pool.PoolFactory; +import lombok.AccessLevel; +import lombok.CustomLog; import lombok.ToString; +import lombok.experimental.FieldDefaults; /** * The default byte buffer allocator. @@ -15,15 +16,15 @@ * @author JavaSaBr */ @ToString +@CustomLog +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public class DefaultBufferAllocator implements BufferAllocator { - private static final Logger LOGGER = LoggerManager.getLogger(DefaultBufferAllocator.class); + final Pool readBufferPool; + final Pool pendingBufferPool; + final Pool writeBufferPool; - protected final Pool readBufferPool; - protected final Pool pendingBufferPool; - protected final Pool writeBufferPool; - - protected final NetworkConfig config; + final NetworkConfig config; public DefaultBufferAllocator(NetworkConfig config) { this.config = config; @@ -34,72 +35,72 @@ public DefaultBufferAllocator(NetworkConfig config) { @Override public ByteBuffer takeReadBuffer() { - var bufferSize = config.getReadBufferSize(); - LOGGER.debug(bufferSize, size -> "Allocate a new read buffer with size: " + size); + int bufferSize = config.readBufferSize(); + log.debug(bufferSize, "Allocate new read buffer with size:[%s]"::formatted); return config.isDirectByteBuffer() ? ByteBuffer.allocateDirect(bufferSize) : ByteBuffer .allocate(bufferSize) - .order(config.getByteOrder()) + .order(config.byteOrder()) .clear(); } @Override public ByteBuffer takePendingBuffer() { - var bufferSize = config.getPendingBufferSize(); - LOGGER.debug(bufferSize, size -> "Allocate a new pending buffer with size: " + size); + int bufferSize = config.pendingBufferSize(); + log.debug(bufferSize, "Allocate new pending buffer with size:[%s]"::formatted); return config.isDirectByteBuffer() ? ByteBuffer.allocateDirect(bufferSize) : ByteBuffer .allocate(bufferSize) - .order(config.getByteOrder()) + .order(config.byteOrder()) .clear(); } @Override public ByteBuffer takeWriteBuffer() { - var bufferSize = config.getWriteBufferSize(); - LOGGER.debug(bufferSize, size -> "Allocate a new write buffer with size: " + size); + int bufferSize = config.writeBufferSize(); + log.debug(bufferSize, "Allocate new write buffer with size:[%s]"::formatted); return config.isDirectByteBuffer() ? ByteBuffer.allocateDirect(bufferSize) : ByteBuffer .allocate(bufferSize) - .order(config.getByteOrder()) + .order(config.byteOrder()) .clear(); } @Override public ByteBuffer takeBuffer(int bufferSize) { - LOGGER.debug(bufferSize, size -> "Allocate a new buffer with size: " + size); + log.debug(bufferSize, "Allocate new buffer with size:[%s]"::formatted); return config.isDirectByteBuffer() ? ByteBuffer.allocateDirect(bufferSize) : ByteBuffer .allocate(bufferSize) - .order(config.getByteOrder()) + .order(config.byteOrder()) .clear(); } @Override public DefaultBufferAllocator putReadBuffer(ByteBuffer buffer) { - LOGGER.debug("Skip storing a read buffer"); + log.debug("Skip storing read buffer"); return this; } @Override public DefaultBufferAllocator putPendingBuffer(ByteBuffer buffer) { - LOGGER.debug("Skip storing a pending buffer"); + log.debug("Skip storing pending buffer"); return this; } @Override public DefaultBufferAllocator putWriteBuffer(ByteBuffer buffer) { - LOGGER.debug("Skip storing a write buffer"); + log.debug("Skip storing write buffer"); return this; } @Override public BufferAllocator putBuffer(ByteBuffer buffer) { - LOGGER.debug("Skip storing a mapped byte buffer"); + log.debug("Skip storing buffer"); return this; } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataConnection.java index 87156783..8d6667cc 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataConnection.java @@ -12,18 +12,22 @@ import javasabr.rlib.network.packet.impl.DefaultNetworkPacketWriter; import lombok.AccessLevel; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; /** * @author JavaSaBr */ @Getter(AccessLevel.PROTECTED) -public abstract class DefaultDataConnection extends - AbstractConnection { +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class DefaultDataConnection + extends AbstractConnection { - private final NetworkPacketReader packetReader; - private final NetworkPacketWriter packetWriter; + final NetworkPacketReader packetReader; + final NetworkPacketWriter packetWriter; - private final int packetLengthHeaderSize; + final int packetLengthHeaderSize; public DefaultDataConnection( Network> network, @@ -56,8 +60,8 @@ protected NetworkPacketWriter createPacketWriter() { bufferAllocator, this::updateLastActivity, this::nextPacketToWrite, - this::onWrittenPacket, - this::onSentPacket, + this::serializedPacket, + this::handleSentPacket, packetLengthHeaderSize); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSSLConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSslConnection.java similarity index 78% rename from rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSSLConnection.java rename to rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSslConnection.java index 7044b892..2708e94a 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSSLConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultDataSslConnection.java @@ -13,20 +13,24 @@ import javax.net.ssl.SSLContext; import lombok.AccessLevel; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; /** * @author JavaSaBr */ @Getter(AccessLevel.PROTECTED) -public abstract class DefaultDataSSLConnection extends - AbstractSSLConnection { +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +public abstract class DefaultDataSslConnection + extends AbstractSslConnection { - private final NetworkPacketReader packetReader; - private final NetworkPacketWriter packetWriter; + final NetworkPacketReader packetReader; + final NetworkPacketWriter packetWriter; - private final int packetLengthHeaderSize; + final int packetLengthHeaderSize; - public DefaultDataSSLConnection( + public DefaultDataSslConnection( Network> network, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, @@ -61,10 +65,9 @@ protected NetworkPacketWriter createPacketWriter() { bufferAllocator, this::updateLastActivity, this::nextPacketToWrite, - this::onWrittenPacket, - this::onSentPacket, + this::serializedPacket, + this::handleSentPacket, sslEngine, - this::sendImpl, this::queueAtFirst, packetLengthHeaderSize); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/IdBasedPacketConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/IdBasedPacketConnection.java index 8584f93e..d71d528a 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/IdBasedPacketConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/IdBasedPacketConnection.java @@ -13,20 +13,24 @@ import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; import lombok.AccessLevel; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; /** * @author JavaSaBr */ @Getter(AccessLevel.PROTECTED) -public class IdBasedPacketConnection, W extends IdBasedWritableNetworkPacket> extends - AbstractConnection { +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +public class IdBasedPacketConnection, W extends IdBasedWritableNetworkPacket> + extends AbstractConnection { - private final NetworkPacketReader packetReader; - private final NetworkPacketWriter packetWriter; - private final ReadableNetworkPacketRegistry packetRegistry; + final NetworkPacketReader packetReader; + final NetworkPacketWriter packetWriter; + final ReadableNetworkPacketRegistry packetRegistry; - private final int packetLengthHeaderSize; - private final int packetIdHeaderSize; + final int packetLengthHeaderSize; + final int packetIdHeaderSize; public IdBasedPacketConnection( Network> network, @@ -64,8 +68,8 @@ protected NetworkPacketWriter createPacketWriter() { bufferAllocator, this::updateLastActivity, this::nextPacketToWrite, - this::onWrittenPacket, - this::onSentPacket, + this::serializedPacket, + this::handleSentPacket, packetLengthHeaderSize, packetIdHeaderSize); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/ReuseBufferAllocator.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/ReuseBufferAllocator.java index 8b578ba3..fa771afa 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/ReuseBufferAllocator.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/ReuseBufferAllocator.java @@ -4,22 +4,20 @@ import java.util.function.Function; import javasabr.rlib.collections.array.ArrayFactory; import javasabr.rlib.collections.array.LockableArray; -import javasabr.rlib.logger.api.Logger; -import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.NetworkConfig; import javasabr.rlib.reusable.pool.Pool; import javasabr.rlib.reusable.pool.PoolFactory; +import lombok.CustomLog; import lombok.ToString; /** * @author JavaSaBr */ @ToString +@CustomLog public class ReuseBufferAllocator implements BufferAllocator { - protected static final Logger LOGGER = LoggerManager.getLogger(ReuseBufferAllocator.class); - protected final Pool readBufferPool; protected final Pool pendingBufferPool; protected final Pool writeBufferPool; @@ -58,39 +56,39 @@ public ByteBuffer takeWriteBuffer() { protected Function pendingBufferFactory() { return config -> { - var bufferSize = config.getPendingBufferSize(); - LOGGER.debug(bufferSize, size -> "Allocate a new pending buffer with size: " + size); + var bufferSize = config.pendingBufferSize(); + log.debug(bufferSize, "Allocate new pending buffer with size:[%s]"::formatted); return config.isDirectByteBuffer() ? ByteBuffer.allocateDirect(bufferSize) : ByteBuffer .allocate(bufferSize) - .order(config.getByteOrder()) + .order(config.byteOrder()) .clear(); }; } protected Function readBufferFactory() { return config -> { - var bufferSize = config.getReadBufferSize(); - LOGGER.debug(bufferSize, size -> "Allocate a new read buffer with size: " + size); + var bufferSize = config.readBufferSize(); + log.debug(bufferSize, "Allocate new read buffer with size:[%s]"::formatted); return config.isDirectByteBuffer() ? ByteBuffer.allocateDirect(bufferSize) : ByteBuffer .allocate(bufferSize) - .order(config.getByteOrder()) + .order(config.byteOrder()) .clear(); }; } protected Function writeBufferFactory() { return config -> { - var bufferSize = config.getWriteBufferSize(); - LOGGER.debug(bufferSize, size -> "Allocate a new write buffer with size: " + size); + var bufferSize = config.writeBufferSize(); + log.debug(bufferSize, "Allocate new write buffer with size:[%s]"::formatted); return config.isDirectByteBuffer() ? ByteBuffer.allocateDirect(bufferSize) : ByteBuffer .allocate(bufferSize) - .order(config.getByteOrder()) + .order(config.byteOrder()) .clear(); }; } @@ -122,7 +120,7 @@ public ByteBuffer takeBuffer(int bufferSize) { // take it from pool if exist if (exist != null && byteBuffers.remove(exist)) { - LOGGER.debug(exist, buffer -> "Reuse old buffer: " + buffer + " - (" + buffer.hashCode() + ")"); + log.debug(exist, buffer -> "Reuse old buffer: " + buffer + " - (" + buffer.hashCode() + ")"); return exist; } @@ -131,12 +129,12 @@ public ByteBuffer takeBuffer(int bufferSize) { } } - LOGGER.debug(bufferSize, size -> "Allocate a new buffer with size: " + size); + log.debug(bufferSize, "Allocate a new buffer with size:[%s]"::formatted); return config.isDirectByteBuffer() ? ByteBuffer.allocateDirect(bufferSize) : ByteBuffer .allocate(bufferSize) - .order(config.getByteOrder()) + .order(config.byteOrder()) .clear(); } @@ -160,7 +158,7 @@ public ReuseBufferAllocator putWriteBuffer(ByteBuffer buffer) { @Override public BufferAllocator putBuffer(ByteBuffer buffer) { - LOGGER.debug(buffer, buf -> "Save used temp buffer: " + buf + " - (" + buf.hashCode() + ")"); + log.debug(buffer, buf -> "Save used temp buffer: " + buf + " - (" + buf.hashCode() + ")"); long stamp = byteBuffers.writeLock(); try { byteBuffers.add(buffer.clear()); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSSLConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSslConnection.java similarity index 83% rename from rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSSLConnection.java rename to rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSslConnection.java index 2a2aa617..c97363da 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSSLConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/StringDataSslConnection.java @@ -11,9 +11,10 @@ /** * @author JavaSaBr */ -public class StringDataSSLConnection extends DefaultDataSSLConnection { +public class StringDataSslConnection extends + DefaultDataSslConnection { - public StringDataSSLConnection( + public StringDataSslConnection( Network> network, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketWriter.java index ecaedef1..a2c1d985 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/NetworkPacketWriter.java @@ -5,7 +5,10 @@ */ public interface NetworkPacketWriter { - void writeNextPacket(); + /** + * @return true if the writer starting writing new data to channel. + */ + boolean tryToSendNextPacket(); /** * Close all used resources. diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java index f87dbcd6..57b17121 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java @@ -23,8 +23,6 @@ import org.jspecify.annotations.Nullable; /** - * @param the readable packet's type. - * @param the connection's type. * @author JavaSaBr */ @CustomLog diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java index 2398a7f6..edc809c3 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java @@ -7,9 +7,9 @@ import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; +import javasabr.rlib.functions.ObjBoolConsumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.NetworkPacketWriter; @@ -29,20 +29,20 @@ @RequiredArgsConstructor @Accessors(fluent = true, chain = false) @FieldDefaults(level = AccessLevel.PROTECTED) -public abstract class AbstractNetworkPacketWriter> implements - NetworkPacketWriter { +public abstract class AbstractNetworkPacketWriter> + implements NetworkPacketWriter { final CompletionHandler writeHandler = new CompletionHandler<>() { @Override public void completed(Integer result, WritableNetworkPacket packet) { - handleSuccessfulWriting(result, packet); + handleSuccessfulWritingData(result, packet); } @Override public void failed(Throwable exc, WritableNetworkPacket packet) { - handleFailedWriting(exc, packet); + handleFailedWritingData(exc, packet); } }; @@ -64,8 +64,8 @@ public void failed(Throwable exc, WritableNetworkPacket packet) { final Runnable updateActivityFunction; final Supplier<@Nullable WritableNetworkPacket> nextWritePacketSupplier; - final BiConsumer sentPacketHandler; - final Consumer packetHandler; + final ObjBoolConsumer sentPacketHandler; + final Consumer serializedToChannelPacketHandler; public AbstractNetworkPacketWriter( C connection, @@ -73,8 +73,8 @@ public AbstractNetworkPacketWriter( BufferAllocator bufferAllocator, Runnable updateActivityFunction, Supplier<@Nullable WritableNetworkPacket> packetProvider, - Consumer packetHandler, - BiConsumer sentPacketHandler) { + Consumer serializedToChannelPacketHandler, + ObjBoolConsumer sentPacketHandler) { this.connection = connection; this.socketChannel = socketChannel; this.bufferAllocator = bufferAllocator; @@ -82,35 +82,38 @@ public AbstractNetworkPacketWriter( this.secondWriteBuffer = bufferAllocator.takeWriteBuffer(); this.updateActivityFunction = updateActivityFunction; this.nextWritePacketSupplier = packetProvider; - this.packetHandler = packetHandler; + this.serializedToChannelPacketHandler = serializedToChannelPacketHandler; this.sentPacketHandler = sentPacketHandler; } @Override - public void writeNextPacket() { - + public boolean tryToSendNextPacket() { if (connection.closed() || !writing.compareAndSet(false, true)) { - return; + return false; } - WritableNetworkPacket waitPacket = nextWritePacketSupplier.get(); - if (waitPacket == null) { + WritableNetworkPacket nextPacket = nextWritePacketSupplier.get(); + if (nextPacket == null) { writing.set(false); - return; + return false; } - ByteBuffer resultBuffer = serialize(waitPacket); + boolean startedWriting = false; + ByteBuffer resultBuffer = serialize(nextPacket); if (resultBuffer.limit() != 0) { writingBuffer = resultBuffer; log.debug(connection.remoteAddress(), resultBuffer, - (address, buf) -> "Write to channel:[%] data:\n" + hexDump(buf)); - socketChannel.write(resultBuffer, waitPacket, writeHandler); + (address, buff) -> "Write to channel:[%] data:\n" + hexDump(buff)); + socketChannel.write(resultBuffer, nextPacket, writeHandler); + startedWriting = true; } else { writing.set(false); } - packetHandler.accept(waitPacket); + serializedToChannelPacketHandler.accept(nextPacket); + + return startedWriting; } /** @@ -166,19 +169,19 @@ protected ByteBuffer serialize( ByteBuffer firstBuffer, ByteBuffer secondBuffer) { - if (!onBeforeWrite(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { + if (!onBeforeSerialize(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { return firstBuffer.clear().limit(0); - } else if (!write(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { + } else if (!doSerialize(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { return firstBuffer.clear().limit(0); - } else if (!onAfterWrite(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { + } else if (!onAfterSerialize(packet, expectedLength, totalSize, firstBuffer, secondBuffer)) { return firstBuffer.clear().limit(0); } - return onResult(packet, expectedLength, totalSize, firstBuffer, secondBuffer); + return onSerializeResult(packet, expectedLength, totalSize, firstBuffer, secondBuffer); } /** - * Handles the buffers before writing packet's data. + * Handles the buffers before serializing packet's data. * * @param packet the network packet. * @param expectedLength the packet's expected size. @@ -187,7 +190,7 @@ protected ByteBuffer serialize( * @param secondBuffer the second buffer. * @return true if handling was successful. */ - protected boolean onBeforeWrite( + protected boolean onBeforeSerialize( W packet, int expectedLength, int totalSize, @@ -198,7 +201,7 @@ protected boolean onBeforeWrite( } /** - * Writes the network packet data to the buffers. + * Serializes the network packet data to the buffers. * * @param packet the network packet. * @param expectedLength the packet's expected size. @@ -207,7 +210,7 @@ protected boolean onBeforeWrite( * @param secondBuffer the second buffer. * @return true if writing was successful. */ - protected boolean write( + protected boolean doSerialize( W packet, int expectedLength, int totalSize, @@ -217,7 +220,7 @@ protected boolean write( } /** - * Handles the buffers after writing packet's data. + * Handles the buffers after serializing packet's data. * * @param packet the network packet. * @param expectedLength the packet's expected size. @@ -226,7 +229,7 @@ protected boolean write( * @param secondBuffer the second buffer. * @return true if handling was successful. */ - protected boolean onAfterWrite( + protected boolean onAfterSerialize( W packet, int expectedLength, int totalSize, @@ -237,7 +240,7 @@ protected boolean onAfterWrite( } /** - * Handles the final result of writing packet data and return the buffer which contains the data to send. + * Handles the final result of serializing packet data and return the buffer which contains the data to send. * * @param packet the network packet. * @param expectedLength the packet's expected size. @@ -246,7 +249,7 @@ protected boolean onAfterWrite( * @param secondBuffer the second buffer. * @return the result buffer. */ - protected ByteBuffer onResult( + protected ByteBuffer onSerializeResult( W packet, int expectedLength, int totalSize, @@ -296,16 +299,16 @@ protected ByteBuffer writeHeader(ByteBuffer buffer, int value, int headerSize) { } /** - * Handles successful wrote data. + * Handles successful writing part of network packet data. * * @param wroteBytes the count of wrote bytes. * @param packet the sent packet. */ - protected void handleSuccessfulWriting(Integer wroteBytes, WritableNetworkPacket packet) { + protected void handleSuccessfulWritingData(Integer wroteBytes, WritableNetworkPacket packet) { updateActivityFunction.run(); if (wroteBytes == -1) { - sentPacketHandler.accept(packet, Boolean.FALSE); + sentPacketHandler.accept(packet, false); connection.close(); return; } @@ -320,14 +323,14 @@ protected void handleSuccessfulWriting(Integer wroteBytes, WritableNetworkPacket log.debug(wroteBytes, "Finished writing [%s] bytes"::formatted); } - sentPacketHandler.accept(packet, Boolean.TRUE); + sentPacketHandler.accept(packet, true); if (writing.compareAndSet(true, false)) { // if we have temp buffers, we can remove it after finishing writing a packet if (firstWriteTempBuffer != null || secondWriteTempBuffer != null) { clearTempBuffers(); } - writeNextPacket(); + tryToSendNextPacket(); } } @@ -337,11 +340,11 @@ protected void handleSuccessfulWriting(Integer wroteBytes, WritableNetworkPacket * @param exception the exception. * @param packet the packet. */ - protected void handleFailedWriting(Throwable exception, WritableNetworkPacket packet) { + protected void handleFailedWritingData(Throwable exception, WritableNetworkPacket packet) { log.error(new RuntimeException("Failed writing packet: " + packet, exception)); if (!connection.closed()) { if (writing.compareAndSet(true, false)) { - writeNextPacket(); + tryToSendNextPacket(); } } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java index 17815f1a..1d5f37ee 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java @@ -9,6 +9,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; +import javasabr.rlib.functions.ObjBoolConsumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.WritableNetworkPacket; @@ -32,7 +33,6 @@ public abstract class AbstractSslNetworkPacketWriter packetWriter; final Consumer queueAtFirst; protected volatile ByteBuffer sslNetworkBuffer; @@ -43,10 +43,9 @@ public AbstractSslNetworkPacketWriter( BufferAllocator bufferAllocator, Runnable updateActivityFunction, Supplier packetProvider, - Consumer writtenPacketHandler, - BiConsumer sentPacketHandler, + Consumer serializedToChannelPacketHandler, + ObjBoolConsumer sentPacketHandler, SSLEngine sslEngine, - Consumer packetWriter, Consumer queueAtFirst) { super( connection, @@ -54,10 +53,9 @@ public AbstractSslNetworkPacketWriter( bufferAllocator, updateActivityFunction, packetProvider, - writtenPacketHandler, + serializedToChannelPacketHandler, sentPacketHandler); this.sslEngine = sslEngine; - this.packetWriter = packetWriter; this.queueAtFirst = queueAtFirst; this.sslNetworkBuffer = bufferAllocator.takeBuffer(sslEngine .getSession() @@ -65,12 +63,12 @@ public AbstractSslNetworkPacketWriter( } @Override - public void writeNextPacket() { + public boolean tryToSendNextPacket() { HandshakeStatus status = sslEngine.getHandshakeStatus(); if (status == HandshakeStatus.NEED_UNWRAP) { - return; + return false; } - super.writeNextPacket(); + return super.tryToSendNextPacket(); } @Override diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketReader.java index cef13e9c..5eb079e5 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketReader.java @@ -12,8 +12,6 @@ import org.jspecify.annotations.Nullable; /** - * @param the readable packet's type. - * @param the connections' type. * @author JavaSaBR */ @FieldDefaults(level = AccessLevel.PROTECTED) diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketWriter.java index c8223853..fe6a1e99 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultNetworkPacketWriter.java @@ -2,14 +2,15 @@ import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; +import javasabr.rlib.functions.ObjBoolConsumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.WritableNetworkPacket; import lombok.AccessLevel; import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; /** * @author JavaSaBr @@ -25,17 +26,17 @@ public DefaultNetworkPacketWriter( AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - Supplier nextWritePacketSupplier, - Consumer writtenPacketHandler, - BiConsumer sentPacketHandler, + Supplier<@Nullable WritableNetworkPacket> packetProvider, + Consumer serializedToChannelPacketHandler, + ObjBoolConsumer sentPacketHandler, int packetLengthHeaderSize) { super( connection, channel, bufferAllocator, updateActivityFunction, - nextWritePacketSupplier, - writtenPacketHandler, + packetProvider, + serializedToChannelPacketHandler, sentPacketHandler); this.packetLengthHeaderSize = packetLengthHeaderSize; } @@ -46,7 +47,7 @@ protected int totalSize(WritableNetworkPacket packet, int expectedLength) { } @Override - protected boolean onBeforeWrite( + protected boolean onBeforeSerialize( W packet, int expectedLength, int totalSize, @@ -59,13 +60,14 @@ protected boolean onBeforeWrite( } @Override - protected ByteBuffer onResult( + protected ByteBuffer onSerializeResult( W packet, int expectedLength, int totalSize, ByteBuffer firstBuffer, ByteBuffer secondBuffer) { - return writePacketLength(firstBuffer, firstBuffer.limit()).position(0); + return writePacketLength(firstBuffer, firstBuffer.limit()) + .position(0); } protected ByteBuffer writePacketLength(ByteBuffer buffer, int packetLength) { diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketReader.java index f4ec8026..0f46f607 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketReader.java @@ -2,35 +2,36 @@ import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; +import java.util.function.Consumer; import java.util.function.IntFunction; -import javasabr.rlib.common.function.NotNullConsumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.ReadableNetworkPacket; import javasabr.rlib.network.packet.WritableNetworkPacket; import javax.net.ssl.SSLEngine; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * @param the readable packet's type. - * @param the connections' type. * @author JavaSaBR */ +@FieldDefaults(level = AccessLevel.PROTECTED) public class DefaultSslNetworkPacketReader> extends AbstractSslNetworkPacketReader { - private final IntFunction readPacketFactory; - private final int packetLengthHeaderSize; + final IntFunction packetResolver; + final int packetLengthHeaderSize; public DefaultSslNetworkPacketReader( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NotNullConsumer readPacketHandler, - IntFunction readPacketFactory, + Consumer packetHandler, + IntFunction packetResolver, SSLEngine sslEngine, - NotNullConsumer packetWriter, + Consumer packetWriter, int packetLengthHeaderSize, int maxPacketsByRead) { super( @@ -38,11 +39,11 @@ public DefaultSslNetworkPacketReader( channel, bufferAllocator, updateActivityFunction, - readPacketHandler, + packetHandler, sslEngine, packetWriter, maxPacketsByRead); - this.readPacketFactory = readPacketFactory; + this.packetResolver = packetResolver; this.packetLengthHeaderSize = packetLengthHeaderSize; } @@ -56,12 +57,13 @@ protected int readFullPacketLength(ByteBuffer buffer) { return readHeader(buffer, packetLengthHeaderSize); } + @Nullable @Override - protected @Nullable R createPacketFor( + protected R createPacketFor( ByteBuffer buffer, int startPacketPosition, int packetFullLength, int packetDataLength) { - return readPacketFactory.apply(packetDataLength); + return packetResolver.apply(packetDataLength); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketWriter.java index ed8f2fda..52438cbe 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultSslNetworkPacketWriter.java @@ -2,33 +2,36 @@ import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; -import javasabr.rlib.common.function.NotNullBiConsumer; -import javasabr.rlib.common.function.NotNullConsumer; -import javasabr.rlib.common.function.NullableSupplier; +import java.util.function.Consumer; +import java.util.function.Supplier; +import javasabr.rlib.functions.ObjBoolConsumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.WritableNetworkPacket; import javax.net.ssl.SSLEngine; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; /** * @author JavaSaBr */ +@FieldDefaults(level = AccessLevel.PROTECTED) public class DefaultSslNetworkPacketWriter> extends AbstractSslNetworkPacketWriter { - protected final int packetLengthHeaderSize; + final int packetLengthHeaderSize; public DefaultSslNetworkPacketWriter( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NullableSupplier nextWritePacketSupplier, - NotNullConsumer writtenPacketHandler, - NotNullBiConsumer sentPacketHandler, + Supplier<@Nullable WritableNetworkPacket> nextWritePacketSupplier, + Consumer serializedToChannelPacketHandler, + ObjBoolConsumer sentPacketHandler, SSLEngine sslEngine, - NotNullConsumer packetWriter, - NotNullConsumer queueAtFirst, + Consumer queueAtFirst, int packetLengthHeaderSize) { super( connection, @@ -36,10 +39,9 @@ public DefaultSslNetworkPacketWriter( bufferAllocator, updateActivityFunction, nextWritePacketSupplier, - writtenPacketHandler, + serializedToChannelPacketHandler, sentPacketHandler, sslEngine, - packetWriter, queueAtFirst); this.packetLengthHeaderSize = packetLengthHeaderSize; } @@ -50,7 +52,7 @@ protected int totalSize(WritableNetworkPacket packet, int expectedLength) { } @Override - protected boolean onBeforeWrite( + protected boolean onBeforeSerialize( W packet, int expectedLength, int totalSize, @@ -63,7 +65,7 @@ protected boolean onBeforeWrite( } @Override - protected ByteBuffer onResult( + protected ByteBuffer onSerializeResult( W packet, int expectedLength, int totalSize, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedNetworkPacketWriter.java index 87cb4c44..7ee8f037 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedNetworkPacketWriter.java @@ -2,30 +2,37 @@ import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; +import java.util.function.Consumer; +import java.util.function.Supplier; import javasabr.rlib.common.function.NotNullBiConsumer; import javasabr.rlib.common.function.NotNullConsumer; import javasabr.rlib.common.function.NullableSupplier; +import javasabr.rlib.functions.ObjBoolConsumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.IdBasedWritableNetworkPacket; import javasabr.rlib.network.packet.WritableNetworkPacket; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; /** * @author JavaSaBr */ -public class IdBasedNetworkPacketWriter> extends - DefaultNetworkPacketWriter { +@FieldDefaults(level = AccessLevel.PROTECTED) +public class IdBasedNetworkPacketWriter> + extends DefaultNetworkPacketWriter { - protected final int packetIdHeaderSize; + final int packetIdHeaderSize; public IdBasedNetworkPacketWriter( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NullableSupplier nextWritePacketSupplier, - NotNullConsumer writtenPacketHandler, - NotNullBiConsumer sentPacketHandler, + Supplier<@Nullable WritableNetworkPacket> packetProvider, + Consumer serializedToChannelPacketHandler, + ObjBoolConsumer sentPacketHandler, int packetLengthHeaderSize, int packetIdHeaderSize) { super( @@ -33,21 +40,21 @@ public IdBasedNetworkPacketWriter( channel, bufferAllocator, updateActivityFunction, - nextWritePacketSupplier, - writtenPacketHandler, + packetProvider, + serializedToChannelPacketHandler, sentPacketHandler, packetLengthHeaderSize); this.packetIdHeaderSize = packetIdHeaderSize; } @Override - protected boolean write( + protected boolean doSerialize( W packet, int expectedLength, int totalSize, ByteBuffer firstBuffer, ByteBuffer secondBuffer) { writeHeader(firstBuffer, packet.packetId(), packetIdHeaderSize); - return super.write(packet, expectedLength, totalSize, firstBuffer, secondBuffer); + return super.doSerialize(packet, expectedLength, totalSize, firstBuffer, secondBuffer); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketReader.java index 029f5708..061b1f04 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/IdBasedPacketReader.java @@ -2,36 +2,37 @@ import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; -import javasabr.rlib.common.function.NotNullConsumer; +import java.util.function.Consumer; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.IdBasedReadableNetworkPacket; import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** - * @param the readable packet's type. - * @param the connection's type. * @author JavaSaBr */ +@FieldDefaults(level = AccessLevel.PROTECTED) public class IdBasedPacketReader, C extends Connection> extends AbstractNetworkPacketReader { - private final ReadableNetworkPacketRegistry packetRegistry; - private final int packetLengthHeaderSize; - private final int packetIdHeaderSize; + final ReadableNetworkPacketRegistry packetRegistry; + final int packetLengthHeaderSize; + final int packetIdHeaderSize; public IdBasedPacketReader( C connection, AsynchronousSocketChannel channel, BufferAllocator bufferAllocator, Runnable updateActivityFunction, - NotNullConsumer readPacketHandler, + Consumer packetHandler, int packetLengthHeaderSize, int maxPacketsByRead, int packetIdHeaderSize, ReadableNetworkPacketRegistry packetRegistry) { - super(connection, channel, bufferAllocator, updateActivityFunction, readPacketHandler, maxPacketsByRead); + super(connection, channel, bufferAllocator, updateActivityFunction, packetHandler, maxPacketsByRead); this.packetLengthHeaderSize = packetLengthHeaderSize; this.packetIdHeaderSize = packetIdHeaderSize; this.packetRegistry = packetRegistry; @@ -47,8 +48,9 @@ protected int readFullPacketLength(ByteBuffer buffer) { return readHeader(buffer, packetLengthHeaderSize); } + @Nullable @Override - protected @Nullable R createPacketFor( + protected R createPacketFor( ByteBuffer buffer, int startPacketPosition, int packetFullLength, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java index f66d229b..ed7c7aad 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java @@ -1,35 +1,36 @@ package javasabr.rlib.network.packet.impl; import java.nio.ByteBuffer; -import javasabr.rlib.network.Connection; +import lombok.AccessLevel; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; /** * @author JavaSaBr */ @Getter -public class StringReadablePacket extends AbstractReadableNetworkPacket> { +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) +public class StringReadablePacket extends AbstractReadableNetworkPacket { - /** - * Read data. - */ - private volatile @Nullable String data; + public static final int MAX_LENGTH = 10_000; + + @Nullable + volatile String data; @Override - protected void readImpl(Connection connection, ByteBuffer buffer) { - this.data = readString(buffer); + protected void readImpl(ByteBuffer buffer) { + this.data = readString(buffer, MAX_LENGTH); } @Override public String toString() { - - var data = getData(); - + String data = data(); if (data != null && data.length() > 20) { data = data.substring(0, 9) + "..." + data.substring(9, 19); } - return "StringReadablePacket(" + "data='" + data + '\'' + ')'; } } diff --git a/rlib-network/src/test/java/javasabr/rlib/network/BaseNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/BaseNetworkTest.java index 69b2ab70..9fc8f5b4 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/BaseNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/BaseNetworkTest.java @@ -5,7 +5,7 @@ import javasabr.rlib.network.impl.DefaultBufferAllocator; import javasabr.rlib.network.impl.DefaultConnection; import javasabr.rlib.network.impl.StringDataConnection; -import javasabr.rlib.network.impl.StringDataSSLConnection; +import javasabr.rlib.network.impl.StringDataSslConnection; import javasabr.rlib.network.packet.impl.DefaultReadableNetworkPacket; import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; import javasabr.rlib.network.server.ServerNetwork; @@ -48,7 +48,7 @@ protected TestNetwork buildStringNetwork() { new DefaultBufferAllocator(NetworkConfig.DEFAULT_CLIENT)); } - protected TestNetwork buildStringSSLNetwork( + protected TestNetwork buildStringSSLNetwork( SSLContext serverSSLContext, SSLContext clientSSLContext) { return buildStringSSLNetwork( @@ -108,7 +108,7 @@ protected TestNetwork buildStringNetwork( clientNetwork); } - protected TestNetwork buildStringSSLNetwork( + protected TestNetwork buildStringSSLNetwork( ServerNetworkConfig serverNetworkConfig, BufferAllocator serverBufferAllocator, SSLContext serverSSLContext, @@ -116,8 +116,8 @@ protected TestNetwork buildStringSSLNetwork( BufferAllocator clientBufferAllocator, SSLContext clientSSLContext) { - var asyncClientToServer = new CompletableFuture(); - var asyncServerToClient = new CompletableFuture(); + var asyncClientToServer = new CompletableFuture(); + var asyncServerToClient = new CompletableFuture(); var serverNetwork = NetworkFactory.stringDataSslServerNetwork( serverNetworkConfig, diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java index c78b7177..b14782df 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java @@ -1,6 +1,5 @@ package javasabr.rlib.network; -import static java.util.stream.Collectors.toList; import static javasabr.rlib.network.ServerNetworkConfig.DEFAULT_SERVER; import java.net.InetSocketAddress; @@ -50,7 +49,7 @@ void echoNetworkTest() { .accepted() .flatMap(Connection::receivedEvents) .subscribe(event -> { - String message = event.packet().getData(); + String message = event.packet().data(); log.info(message, "Received from client:[%s]"::formatted); event.connection().send(new StringWritableNetworkPacket("Echo: " + message)); }); @@ -63,7 +62,7 @@ void echoNetworkTest() { .forEach(length -> connection.send(new StringWritableNetworkPacket(StringUtils.generate(length))))) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { - log.info(event.packet().getData(), "Received from server:[%s]"::formatted); + log.info(event.packet().data(), "Received from server:[%s]"::formatted); counter.countDown(); }); @@ -127,7 +126,7 @@ public ByteBuffer takeBuffer(int bufferSize) { .stream() .filter(packet -> messages .stream() - .noneMatch(message -> message.equals(packet.getData()))) + .noneMatch(message -> message.equals(packet.data()))) .findFirst() .orElse(null); @@ -172,7 +171,7 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { .stream() .filter(packet -> messages .stream() - .noneMatch(message -> message.equals(packet.getData()))) + .noneMatch(message -> message.equals(packet.data()))) .findFirst() .orElse(null); @@ -221,7 +220,7 @@ void shouldSendBiggerPacketThanWriteBuffer() { .stream() .filter(packet -> messages .stream() - .noneMatch(message -> message.equals(packet.getData()))) + .noneMatch(message -> message.equals(packet.data()))) .findFirst() .orElse(null); diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java index 4fcbc359..62c9bb1c 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java @@ -1,13 +1,14 @@ package javasabr.rlib.network; -import static java.util.stream.Collectors.toList; -import static javasabr.rlib.network.NetworkFactory.newStringDataSSLClientNetwork; -import static javasabr.rlib.network.NetworkFactory.newStringDataSSLServerNetwork; - +import java.io.InputStream; +import java.io.OutputStream; import java.io.PrintWriter; import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; import java.nio.ByteBuffer; import java.time.Duration; +import java.util.List; import java.util.Scanner; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadLocalRandom; @@ -19,13 +20,19 @@ import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.api.LoggerManager; +import javasabr.rlib.network.client.ClientNetwork; import javasabr.rlib.network.impl.DefaultBufferAllocator; +import javasabr.rlib.network.impl.StringDataSslConnection; import javasabr.rlib.network.packet.impl.AbstractSslNetworkPacketReader; import javasabr.rlib.network.packet.impl.AbstractSslNetworkPacketWriter; import javasabr.rlib.network.packet.impl.StringReadablePacket; import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; +import javasabr.rlib.network.server.ServerNetwork; import javasabr.rlib.network.util.NetworkUtils; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -43,17 +50,17 @@ public class StringSSLNetworkTest extends BaseNetworkTest { @SneakyThrows void certificatesTest() { - var keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); - var sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); - var clientSSLContext = NetworkUtils.createAllTrustedClientSslContext(); + InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + SSLContext sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); + SSLContext clientSSLContext = NetworkUtils.createAllTrustedClientSslContext(); - var serverPort = NetworkUtils.getAvailablePort(10000); + int serverPort = NetworkUtils.getAvailablePort(10000); - var serverSocketFactory = sslContext.getServerSocketFactory(); - var serverSocket = serverSocketFactory.createServerSocket(serverPort); + SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory(); + ServerSocket serverSocket = serverSocketFactory.createServerSocket(serverPort); - var clientSocketFactory = clientSSLContext.getSocketFactory(); - var clientSocket = (SSLSocket) clientSocketFactory.createSocket("localhost", serverPort); + SSLSocketFactory clientSocketFactory = clientSSLContext.getSocketFactory(); + SSLSocket clientSocket = (SSLSocket) clientSocketFactory.createSocket("localhost", serverPort); var clientSocketOnServer = serverSocket.accept(); @@ -63,8 +70,8 @@ void certificatesTest() { clientOutStream.flush(); })).start(); - var serverIn = new Scanner(clientSocketOnServer.getInputStream()); - var receivedOnServer = serverIn.next() + " " + serverIn.next(); + Scanner serverIn = new Scanner(clientSocketOnServer.getInputStream()); + String receivedOnServer = serverIn.next() + " " + serverIn.next(); Assertions.assertEquals("Hello SSL", receivedOnServer); } @@ -73,28 +80,28 @@ void certificatesTest() { @SneakyThrows void serverSSLNetworkTest() { - var keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); - var sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); + InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + SSLContext sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); - var serverNetwork = newStringDataSSLServerNetwork( + ServerNetwork serverNetwork = NetworkFactory.stringDataSslServerNetwork( ServerNetworkConfig.DEFAULT_SERVER, new DefaultBufferAllocator(ServerNetworkConfig.DEFAULT_CLIENT), sslContext); - var serverAddress = serverNetwork.start(); + InetSocketAddress serverAddress = serverNetwork.start(); serverNetwork .accepted() .flatMap(Connection::receivedEvents) .subscribe(event -> { - var message = event.packet.getData(); + var message = event.packet().data(); LOGGER.info("Received from client: " + message); - event.connection.send(new StringWritableNetworkPacket("Echo: " + message)); + event.connection().send(new StringWritableNetworkPacket("Echo: " + message)); }); - var clientSslContext = NetworkUtils.createAllTrustedClientSslContext(); - var sslSocketFactory = clientSslContext.getSocketFactory(); - var sslSocket = (SSLSocket) sslSocketFactory.createSocket(serverAddress.getHostName(), serverAddress.getPort()); + SSLContext clientSslContext = NetworkUtils.createAllTrustedClientSslContext(); + SSLSocketFactory sslSocketFactory = clientSslContext.getSocketFactory(); + SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(serverAddress.getHostName(), serverAddress.getPort()); var buffer = ByteBuffer.allocate(1024); buffer.position(2); @@ -110,18 +117,18 @@ void serverSSLNetworkTest() { buffer.clear(); - var in = sslSocket.getInputStream(); - var readBytes = in.read(buffer.array()); + InputStream in = sslSocket.getInputStream(); + int readBytes = in.read(buffer.array()); buffer .position(readBytes) .flip(); - var packetLength = buffer.getShort(); + short packetLength = buffer.getShort(); - var response = new StringReadablePacket(); - response.read(null, buffer, packetLength - 2); + StringReadablePacket response = new StringReadablePacket(); + response.read(buffer, packetLength - 2); - LOGGER.info("Response: " + response.getData()); + LOGGER.info("Response: " + response.data()); serverNetwork.shutdown(); } @@ -134,37 +141,37 @@ void clientSSLNetworkTest() { //LoggerManager.enable(AbstractSSLPacketWriter.class, LoggerLevel.DEBUG); //LoggerManager.enable(AbstractSSLPacketReader.class, LoggerLevel.DEBUG); - var keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); - var sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); + InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + SSLContext sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); - var serverPort = NetworkUtils.getAvailablePort(1000); + int serverPort = NetworkUtils.getAvailablePort(1000); - var serverSocketFactory = sslContext.getServerSocketFactory(); - var serverSocket = serverSocketFactory.createServerSocket(serverPort); - var counter = new CountDownLatch(1); + SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory(); + ServerSocket serverSocket = serverSocketFactory.createServerSocket(serverPort); + CountDownLatch counter = new CountDownLatch(1); - var clientSslContext = NetworkUtils.createAllTrustedClientSslContext(); - var clientNetwork = newStringDataSSLClientNetwork( + SSLContext clientSslContext = NetworkUtils.createAllTrustedClientSslContext(); + ClientNetwork clientNetwork = NetworkFactory.stringDataSslClientNetwork( NetworkConfig.DEFAULT_CLIENT, new DefaultBufferAllocator(NetworkConfig.DEFAULT_CLIENT), clientSslContext); clientNetwork - .connected(new InetSocketAddress("localhost", serverPort)) + .connectReactive(new InetSocketAddress("localhost", serverPort)) .doOnNext(connection -> connection.send(new StringWritableNetworkPacket("Hello SSL"))) .doOnError(Throwable::printStackTrace) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { - LOGGER.info("Received from server: " + event.packet.getData()); + LOGGER.info("Received from server: " + event.packet().data()); counter.countDown(); }); - var acceptedClientSocket = serverSocket.accept(); + Socket acceptedClientSocket = serverSocket.accept(); var buffer = ByteBuffer.allocate(512); - var clientIn = acceptedClientSocket.getInputStream(); - var readBytes = clientIn.read(buffer.array()); + InputStream clientIn = acceptedClientSocket.getInputStream(); + int readBytes = clientIn.read(buffer.array()); buffer .position(readBytes) @@ -173,11 +180,11 @@ void clientSSLNetworkTest() { var dataLength = buffer.getShort(); var receivedPacket = new StringReadablePacket(); - receivedPacket.read(null, buffer, dataLength); + receivedPacket.read(buffer, dataLength); - Assertions.assertEquals("Hello SSL", receivedPacket.getData()); + Assertions.assertEquals("Hello SSL", receivedPacket.data()); - LOGGER.info("Received from client: " + receivedPacket.getData()); + LOGGER.info("Received from client: " + receivedPacket.data()); buffer.clear(); buffer.position(2); @@ -187,7 +194,7 @@ void clientSSLNetworkTest() { buffer.putShort(0, (short) buffer.position()); buffer.flip(); - var out = acceptedClientSocket.getOutputStream(); + OutputStream out = acceptedClientSocket.getOutputStream(); out.write(buffer.array(), 0, buffer.limit()); out.flush(); @@ -210,42 +217,43 @@ void echoNetworkTest() { //LoggerManager.enable(AbstractSSLPacketWriter.class, LoggerLevel.DEBUG); //LoggerManager.enable(AbstractSSLPacketReader.class, LoggerLevel.DEBUG); - var keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); - var serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); + InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + SSLContext serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); - var serverNetwork = newStringDataSSLServerNetwork( + ServerNetwork serverNetwork = NetworkFactory.stringDataSslServerNetwork( ServerNetworkConfig.DEFAULT_SERVER, new DefaultBufferAllocator(ServerNetworkConfig.DEFAULT_CLIENT), serverSSLContext); - var expectedReceivedPackets = 90; - var serverAddress = serverNetwork.start(); + InetSocketAddress serverAddress = serverNetwork.start(); + int expectedReceivedPackets = 90; + var counter = new CountDownLatch(expectedReceivedPackets); serverNetwork .accepted() .flatMap(Connection::receivedEvents) .subscribe(event -> { - var message = event.packet.getData(); + var message = event.packet().data(); LOGGER.info("Received from client: " + message); - event.connection.send(new StringWritableNetworkPacket("Echo: " + message)); + event.connection().send(new StringWritableNetworkPacket("Echo: " + message)); }); - var clientSslContext = NetworkUtils.createAllTrustedClientSslContext(); - var clientNetwork = newStringDataSSLClientNetwork( + SSLContext clientSslContext = NetworkUtils.createAllTrustedClientSslContext(); + ClientNetwork clientNetwork = NetworkFactory.stringDataSslClientNetwork( NetworkConfig.DEFAULT_CLIENT, new DefaultBufferAllocator(NetworkConfig.DEFAULT_CLIENT), clientSslContext); clientNetwork - .connected(serverAddress) + .connectReactive(serverAddress) .doOnNext(connection -> IntStream .range(10, expectedReceivedPackets + 10) .forEach(length -> connection.send(newMessage(9, length)))) .doOnError(Throwable::printStackTrace) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { - LOGGER.info("Received from server: " + event.packet.getData()); + LOGGER.info("Received from server: " + event.packet().data()); counter.countDown(); }); @@ -270,24 +278,22 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { LoggerManager.enable(AbstractSslNetworkPacketWriter.class, LoggerLevel.DEBUG); LoggerManager.enable(AbstractSslNetworkPacketReader.class, LoggerLevel.DEBUG); - var keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); - var serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); - var clientSSLContext = NetworkUtils.createAllTrustedClientSslContext(); + InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + SSLContext serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); + SSLContext clientSSLContext = NetworkUtils.createAllTrustedClientSslContext(); int packetCount = 10; - try (var testNetwork = buildStringSSLNetwork(serverSSLContext, clientSSLContext)) { - - var bufferSize = testNetwork.serverNetworkConfig.getReadBufferSize(); - + try (TestNetwork testNetwork = buildStringSSLNetwork(serverSSLContext, clientSSLContext)) { + var bufferSize = testNetwork.serverNetworkConfig.readBufferSize(); var random = ThreadLocalRandom.current(); - var clientToServer = testNetwork.clientToServer; - var serverToClient = testNetwork.serverToClient; + StringDataSslConnection clientToServer = testNetwork.clientToServer; + StringDataSslConnection serverToClient = testNetwork.serverToClient; var pendingPacketsOnServer = serverToClient .receivedPackets() - .doOnNext(packet -> LOGGER.info("Received from client: " + packet.getData())) + .doOnNext(packet -> LOGGER.info("Received from client: " + packet.data())) .buffer(packetCount); var messages = IntStream @@ -297,17 +303,18 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { return StringUtils.generate(length); }) .peek(message -> clientToServer.send(new StringWritableNetworkPacket(message))) - .collect(toList()); + .toList(); - var receivedPackets = ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5000))); + List receivedPackets = + ObjectUtils.notNull(pendingPacketsOnServer.blockFirst(Duration.ofSeconds(5000))); - Assertions.assertEquals(receivedPackets.size(), packetCount, "Didn't receive all packets"); + Assertions.assertEquals(packetCount, receivedPackets.size(), "Didn't receive all packets"); var wrongPacket = receivedPackets .stream() .filter(packet -> messages .stream() - .noneMatch(message -> message.equals(packet.getData()))) + .noneMatch(message -> message.equals(packet.data()))) .findFirst() .orElse(null); From 6f42492298e44c4aa89b6aa4617c0369baa3188e Mon Sep 17 00:00:00 2001 From: javasabr Date: Fri, 3 Oct 2025 20:48:50 +0200 Subject: [PATCH 04/15] continue working on network and fix dequeues --- .../deque/impl/AbstractArrayBasedDeque.java | 22 +- .../deque/impl/DefaultArrayBasedDeque.java | 5 + .../deque/impl/LinkedListIterator.java | 11 + .../rlib/collections/deque/DequeTest.java | 217 ++++++++++++------ .../java/javasabr/rlib/logger/api/Logger.java | 73 +++++- .../javasabr/rlib/network/Connection.java | 8 +- .../rlib/network/impl/AbstractConnection.java | 11 +- .../rlib/network/impl/DefaultConnection.java | 3 +- .../network/packet/ReadableNetworkPacket.java | 4 +- .../impl/AbstractNetworkPacketReader.java | 83 ++++--- .../impl/AbstractNetworkPacketWriter.java | 19 +- .../impl/AbstractReadableNetworkPacket.java | 4 +- .../impl/DefaultReadableNetworkPacket.java | 4 - .../ReadableNetworkPacketRegistry.java | 19 +- .../rlib/network/DefaultNetworkTest.java | 34 ++- .../rlib/network/StringNetworkTest.java | 33 ++- 16 files changed, 400 insertions(+), 150 deletions(-) diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java index 96984cfc..008a22d3 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/AbstractArrayBasedDeque.java @@ -111,6 +111,8 @@ public boolean offerLast(E element) { protected abstract void incrementSize(); protected abstract void decrementSize(); + protected abstract int decrementSizeAndGet(); + protected @Nullable E[] increaseLeft(@Nullable E[] items, int size) { int stepSize = stepSize(items); @@ -177,13 +179,17 @@ public E removeFirst() { E item = items[head]; items[head] = null; - decrementSize(); - int newHead = incrementHeadAndGet(); + int newSize = decrementSizeAndGet(); + if (newSize == 0) { + resetIndexes(); + //noinspection DataFlowIssue + return item; + } + int newHead = incrementHeadAndGet(); if (head == tail()) { tail(newHead); } - if (newHead > rebalanceTrigger()) { rebalance(); } @@ -205,13 +211,17 @@ public E removeLast() { E item = items[tail]; items[tail] = null; - decrementSize(); - int newTail = decrementTailAndGet(); + int newSize = decrementSizeAndGet(); + if (newSize == 0) { + resetIndexes(); + //noinspection DataFlowIssue + return item; + } + int newTail = decrementTailAndGet(); if (tail == head()) { head(newTail); } - if (items.length - tail > rebalanceTrigger()) { rebalance(); } diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/DefaultArrayBasedDeque.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/DefaultArrayBasedDeque.java index b53048dd..9c433f75 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/DefaultArrayBasedDeque.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/DefaultArrayBasedDeque.java @@ -60,4 +60,9 @@ protected void incrementSize() { protected void decrementSize() { size--; } + + @Override + protected int decrementSizeAndGet() { + return --size; + } } diff --git a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/LinkedListIterator.java b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/LinkedListIterator.java index e85731c8..d3e64251 100644 --- a/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/LinkedListIterator.java +++ b/rlib-collections/src/main/java/javasabr/rlib/collections/deque/impl/LinkedListIterator.java @@ -18,6 +18,8 @@ public class LinkedListIterator implements Iterator { @Nullable LinkedNode next; + @Nullable + LinkedNode current; public LinkedListIterator(AbstractLinkedListBasedDeque linkedList, int mode) { if (mode == NEXT) { @@ -43,7 +45,16 @@ public E next() { throw new NoSuchElementException(); } E item = next.item; + current = next; next = nextFunction.apply(next); return item; } + + @Override + public void remove() { + if (current == null) { + throw new NoSuchElementException(); + } + linkedList.unlink(current); + } } diff --git a/rlib-collections/src/test/java/javasabr/rlib/collections/deque/DequeTest.java b/rlib-collections/src/test/java/javasabr/rlib/collections/deque/DequeTest.java index 5752a16b..0999ca2f 100644 --- a/rlib-collections/src/test/java/javasabr/rlib/collections/deque/DequeTest.java +++ b/rlib-collections/src/test/java/javasabr/rlib/collections/deque/DequeTest.java @@ -11,6 +11,9 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; import java.util.stream.Stream; import javasabr.rlib.collections.array.MutableArray; import javasabr.rlib.common.util.ReflectionUtils; @@ -55,6 +58,82 @@ void shouldAddFirst(Deque deque) { "val7", "val6", "val5", "val4", "val3", "val2", "val1")); } + @ParameterizedTest + @MethodSource("generateDeque") + void shouldAddFirstManyElements(Deque deque) { + + // when: + IntStream.range(1, 200) + .mapToObj(value -> "val_" + value) + .forEach(deque::addFirst); + + // then: + assertEquals(199, deque.size()); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldAddLastManyElements(Deque deque) { + + // when: + IntStream.range(1, 200) + .mapToObj(value -> "val_" + value) + .forEach(deque::addLast); + + // then: + assertEquals(199, deque.size()); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldAddFirstLastManyElements(Deque deque) { + + // when: + IntStream + .range(1, 500) + .mapToObj(value -> "val_" + value) + .forEach(value -> { + if (ThreadLocalRandom.current().nextBoolean()) { + deque.addFirst(value); + } else { + deque.addLast(value); + } + }); + + // then: + assertEquals(499, deque.size()); + } + + @ParameterizedTest + @MethodSource("generateDeque") + void shouldAddLastRemoveFirstManyElements(Deque deque) { + int count = 10; + // when/then: + IntStream + .range(1, count) + .forEach(value -> deque.addLast("value_%d".formatted(value))); + + // when/then: + IntStream + .range(1, count) + .forEach(value -> deque.removeFirst()); + + // when/then: + IntStream + .range(1, count) + .forEach(value -> deque.addLast("value_%d".formatted(value))); + + // when/then: + IntStream + .range(1, count) + .forEach(value -> deque.removeFirst()); + + // when/then: + IntStream + .range(1, count) + .forEach(value -> deque.addLast("value_%d".formatted(value))); + } + @ParameterizedTest @MethodSource("generateDeque") void shouldAddLast(Deque deque) { @@ -302,10 +381,11 @@ void shouldRebalanceIndexesAddLastRemoveFirst() { Deque deque = DequeFactory.arrayBasedBased(String.class, 15); Field head = ReflectionUtils.getUnsafeField(deque, "head"); Field tail = ReflectionUtils.getUnsafeField(deque, "tail"); + var generator = new AtomicInteger(); // when: - for (int i = 1; i < 12; i++) { - deque.addLast("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addLast("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeFirst(); @@ -316,12 +396,12 @@ void shouldRebalanceIndexesAddLastRemoveFirst() { // then: assertEquals(18, headValue); - assertEquals(18, tailValue); - assertEquals(0, deque.size()); + assertEquals(19, tailValue); + assertEquals(2, deque.size()); // when: - for (int i = 12; i < 24; i++) { - deque.addLast("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addLast("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeFirst(); @@ -332,12 +412,12 @@ void shouldRebalanceIndexesAddLastRemoveFirst() { // then: assertEquals(29, headValue); - assertEquals(29, tailValue); - assertEquals(1, deque.size()); + assertEquals(32, tailValue); + assertEquals(4, deque.size()); // when: - for (int i = 24; i < 36; i++) { - deque.addLast("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addLast("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeFirst(); @@ -348,12 +428,12 @@ void shouldRebalanceIndexesAddLastRemoveFirst() { // then: assertEquals(40, headValue); - assertEquals(41, tailValue); - assertEquals(2, deque.size()); + assertEquals(45, tailValue); + assertEquals(6, deque.size()); // when: - for (int i = 36; i < 48; i++) { - deque.addLast("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addLast("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeFirst(); @@ -363,13 +443,13 @@ void shouldRebalanceIndexesAddLastRemoveFirst() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(51, headValue); - assertEquals(53, tailValue); - assertEquals(3, deque.size()); + assertEquals(31, headValue); + assertEquals(38, tailValue); + assertEquals(8, deque.size()); // when: - for (int i = 48; i < 60; i++) { - deque.addLast("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addLast("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeFirst(); @@ -379,13 +459,13 @@ void shouldRebalanceIndexesAddLastRemoveFirst() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(40, headValue); - assertEquals(43, tailValue); - assertEquals(4, deque.size()); + assertEquals(42, headValue); + assertEquals(51, tailValue); + assertEquals(10, deque.size()); // when: - for (int i = 60; i < 72; i++) { - deque.addLast("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addLast("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeFirst(); @@ -395,13 +475,13 @@ void shouldRebalanceIndexesAddLastRemoveFirst() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(51, headValue); - assertEquals(55, tailValue); - assertEquals(5, deque.size()); + assertEquals(30, headValue); + assertEquals(41, tailValue); + assertEquals(12, deque.size()); // when: - for (int i = 60; i < 72; i++) { - deque.addLast("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addLast("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeFirst(); @@ -411,9 +491,9 @@ void shouldRebalanceIndexesAddLastRemoveFirst() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(39, headValue); - assertEquals(44, tailValue); - assertEquals(6, deque.size()); + assertEquals(41, headValue); + assertEquals(54, tailValue); + assertEquals(14, deque.size()); } @Test @@ -423,10 +503,11 @@ void shouldRebalanceIndexesAddFirstRemoveLast() { Deque deque = DequeFactory.arrayBasedBased(String.class, 15); Field head = ReflectionUtils.getUnsafeField(deque, "head"); Field tail = ReflectionUtils.getUnsafeField(deque, "tail"); + var generator = new AtomicInteger(); // when: - for (int i = 1; i < 12; i++) { - deque.addFirst("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addFirst("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeLast(); @@ -436,13 +517,13 @@ void shouldRebalanceIndexesAddFirstRemoveLast() { int tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(6, headValue); + assertEquals(5, headValue); assertEquals(6, tailValue); - assertEquals(0, deque.size()); + assertEquals(2, deque.size()); // when: - for (int i = 12; i < 24; i++) { - deque.addFirst("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addFirst("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeLast(); @@ -452,13 +533,13 @@ void shouldRebalanceIndexesAddFirstRemoveLast() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(5, headValue); + assertEquals(2, headValue); assertEquals(5, tailValue); - assertEquals(1, deque.size()); + assertEquals(4, deque.size()); // when: - for (int i = 24; i < 36; i++) { - deque.addFirst("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addFirst("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeLast(); @@ -468,13 +549,13 @@ void shouldRebalanceIndexesAddFirstRemoveLast() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(3, headValue); - assertEquals(4, tailValue); - assertEquals(2, deque.size()); + assertEquals(9, headValue); + assertEquals(14, tailValue); + assertEquals(6, deque.size()); // when: - for (int i = 36; i < 48; i++) { - deque.addFirst("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addFirst("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeLast(); @@ -484,13 +565,13 @@ void shouldRebalanceIndexesAddFirstRemoveLast() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(1, headValue); - assertEquals(3, tailValue); - assertEquals(3, deque.size()); + assertEquals(25, headValue); + assertEquals(32, tailValue); + assertEquals(8, deque.size()); // when: - for (int i = 48; i < 60; i++) { - deque.addFirst("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addFirst("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeLast(); @@ -500,13 +581,13 @@ void shouldRebalanceIndexesAddFirstRemoveLast() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(31, headValue); - assertEquals(34, tailValue); - assertEquals(4, deque.size()); + assertEquals(12, headValue); + assertEquals(21, tailValue); + assertEquals(10, deque.size()); // when: - for (int i = 60; i < 72; i++) { - deque.addFirst("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addFirst("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeLast(); @@ -516,13 +597,13 @@ void shouldRebalanceIndexesAddFirstRemoveLast() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(19, headValue); - assertEquals(23, tailValue); - assertEquals(5, deque.size()); + assertEquals(31, headValue); + assertEquals(42, tailValue); + assertEquals(12, deque.size()); // when: - for (int i = 60; i < 72; i++) { - deque.addFirst("val%s".formatted(i)); + for (int i = 1; i < 14; i++) { + deque.addFirst("val%s".formatted(generator.incrementAndGet())); } for (int i = 1; i < 12; i++) { deque.removeLast(); @@ -532,9 +613,9 @@ void shouldRebalanceIndexesAddFirstRemoveLast() { tailValue = ReflectionUtils.getFieldValue(deque, tail); // then: - assertEquals(30, headValue); - assertEquals(35, tailValue); - assertEquals(6, deque.size()); + assertEquals(18, headValue); + assertEquals(31, tailValue); + assertEquals(14, deque.size()); } @ParameterizedTest @@ -577,13 +658,13 @@ void shouldCorrectlyIterate2Deque(Deque deque) { } // then: - assertArrayEquals(container.toArray(), array("val6", "val5", "val4", "val3", "val2", "val1")); - assertArrayEquals(deque.toArray(), array("val1", "val3", "val5", "val6")); + // assertArrayEquals(container.toArray(), array("val6", "val5", "val4", "val3", "val2", "val1")); + assertArrayEquals(array("val1", "val3", "val5", "val6"), deque.toArray()); } private static Stream generateDeque() { return Stream.of( - //Arguments.of(DequeFactory.linkedListBased()), + Arguments.of(DequeFactory.linkedListBased()), Arguments.of(DequeFactory.arrayBasedBased(String.class, 15))); } } diff --git a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java index ffd0b5fb..dae4343e 100644 --- a/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java +++ b/rlib-logger-api/src/main/java/javasabr/rlib/logger/api/Logger.java @@ -51,6 +51,20 @@ interface N1IntFactory { String make(A arg1, int arg2); } + @FunctionalInterface + interface N1Int2Factory { + + @NonNull + String make(A arg1, int arg2, int arg3); + } + + @FunctionalInterface + interface N1IntN1Factory { + + @NonNull + String make(A arg1, int arg2, C arg3); + } + @FunctionalInterface interface Int2Factory { @@ -72,6 +86,13 @@ interface Int2N1Factory { String make(int arg1, int arg2, C arg3); } + @FunctionalInterface + interface N1Int2N1Factory { + + @NonNull + String make(A arg1, int arg2, int arg3, D arg4); + } + @FunctionalInterface interface N4Factory { @@ -112,7 +133,15 @@ default void debug(int arg1, int arg2, @NonNull Int2Factory factory) { print(LoggerLevel.DEBUG, arg1, arg2, factory); } - default void debug(F arg1, S arg2, T arg3, @NonNull N3Factory factory) { + default void debug(A arg1, B arg2, C arg3, @NonNull N3Factory factory) { + print(LoggerLevel.DEBUG, arg1, arg2, arg3, factory); + } + + default void debug(A arg1, int arg2, C arg3, @NonNull N1IntN1Factory factory) { + print(LoggerLevel.DEBUG, arg1, arg2, arg3, factory); + } + + default void debug(A arg1, int arg2, int arg3, @NonNull N1Int2Factory factory) { print(LoggerLevel.DEBUG, arg1, arg2, arg3, factory); } @@ -132,10 +161,18 @@ default void error(int arg1, B arg2, @NonNull IntN1Factory factory) { print(LoggerLevel.ERROR, arg1, arg2, factory); } + default void error(A arg1, B arg2, @NonNull N2Factory factory) { + print(LoggerLevel.ERROR, arg1, arg2, factory); + } + default void error(int arg1, int arg2, C arg3, @NonNull Int2N1Factory factory) { print(LoggerLevel.ERROR, arg1, arg2, arg3, factory); } + default void error(A arg1, int arg2, int arg3, D arg4, @NonNull N1Int2N1Factory factory) { + print(LoggerLevel.ERROR, arg1, arg2, arg3, arg4, factory); + } + default void error(@NonNull Throwable exception) { print(LoggerLevel.ERROR, exception); } @@ -283,6 +320,28 @@ default void print( } } + default void print( + @NonNull LoggerLevel level, + A arg1, + int arg2, + C arg3, + @NonNull N1IntN1Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2, arg3)); + } + } + + default void print( + @NonNull LoggerLevel level, + A arg1, + int arg2, + int arg3, + @NonNull N1Int2Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2, arg3)); + } + } + default void print( @NonNull LoggerLevel level, int arg1, @@ -294,6 +353,18 @@ default void print( } } + default void print( + @NonNull LoggerLevel level, + A arg1, + int arg2, + int arg3, + D arg4, + @NonNull N1Int2N1Factory factory) { + if (enabled(level)) { + print(level, factory.make(arg1, arg2, arg3, arg4)); + } + } + default void print( @NonNull LoggerLevel level, A arg1, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/Connection.java b/rlib-network/src/main/java/javasabr/rlib/network/Connection.java index 6e6a0669..af7eb4bc 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/Connection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/Connection.java @@ -14,7 +14,13 @@ public interface Connection { record ReceivedPacketEvent, R extends ReadableNetworkPacket>( - C connection, R packet) {} + C connection, R packet) { + + @Override + public String toString() { + return "[" + connection + "|" + packet + ']'; + } + } /** * Get a remote address of this connection. diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java index 1e32fbbc..26c78c55 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/AbstractConnection.java @@ -177,7 +177,7 @@ protected void handleReceivedPacket(R packet) { .forEach(this, packet, BiConsumer::accept); } - protected void handleSentPacket(WritableNetworkPacket packet, Boolean result) { + protected void handleSentPacket(WritableNetworkPacket packet, boolean result) { if (packet instanceof WritablePacketWithFeedback) { ((WritablePacketWithFeedback) packet) .getAttachment() @@ -198,7 +198,7 @@ protected void sendImpl(WritableNetworkPacket packet) { long stamp = lock.writeLock(); try { - pendingPackets.add(packet); + pendingPackets.addLast(packet); } finally { lock.unlockWrite(stamp); } @@ -244,9 +244,14 @@ protected void clearWaitPackets() { protected void doClearWaitPackets() { for (var pendingPacket : pendingPackets) { - handleSentPacket(pendingPacket, Boolean.FALSE); + handleSentPacket(pendingPacket, false); } pendingPackets.clear(); } + + @Override + public String toString() { + return "{" + remoteAddress + '}'; + } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultConnection.java b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultConnection.java index 1d1f597b..26a404ad 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultConnection.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/impl/DefaultConnection.java @@ -11,7 +11,8 @@ /** * @author JavaSaBr */ -public class DefaultConnection extends IdBasedPacketConnection { +public class DefaultConnection extends + IdBasedPacketConnection { public DefaultConnection( Network> network, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/ReadableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/ReadableNetworkPacket.java index 9816e686..9438e58a 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/ReadableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/ReadableNetworkPacket.java @@ -13,8 +13,8 @@ public interface ReadableNetworkPacket extends NetworkPacket { * Read packet's data from byte buffer. * * @param buffer the buffer with received data. - * @param expectedLength the expected data length. + * @param remainingDataLength the expected remaining data length. * @return true if reading was success. */ - boolean read(ByteBuffer buffer, int expectedLength); + boolean read(ByteBuffer buffer, int remainingDataLength); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java index 57b17121..c6abe8e3 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java @@ -13,7 +13,6 @@ import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.NetworkPacketReader; import javasabr.rlib.network.packet.ReadableNetworkPacket; -import javasabr.rlib.network.util.NetworkUtils; import lombok.AccessLevel; import lombok.CustomLog; import lombok.Getter; @@ -84,12 +83,16 @@ protected ByteBuffer bufferToReadFromChannel() { return readBuffer; } + protected String remoteAddress() { + return connection.remoteAddress(); + } + @Override public void startRead() { if (!reading.compareAndSet(false, true)) { return; } - log.debug(socketChannel, ch -> "Start waiting for new data from channel:[" + NetworkUtils.getRemoteAddress(ch) + "]"); + log.debug(remoteAddress(), "[%s] Start waiting for new data from channel..."::formatted); ByteBuffer buffer = bufferToReadFromChannel(); socketChannel.read(buffer, buffer, readChannelHandler); } @@ -112,7 +115,10 @@ protected int readPackets(ByteBuffer receivedBuffer) { * @return count of read packets. */ protected int readPackets(ByteBuffer receivedBuffer, ByteBuffer pendingBuffer) { - log.debug(receivedBuffer, "Start reading packets from received buffer:[%s]"::formatted); + String remoteAddress = remoteAddress(); + + log.debug(remoteAddress, receivedBuffer, + "[%s] Start reading packets from received buffer:[%s]"::formatted); int waitedBytes = pendingBuffer.position(); ByteBuffer bufferToRead = receivedBuffer; @@ -126,7 +132,10 @@ protected int readPackets(ByteBuffer receivedBuffer, ByteBuffer pendingBuffer) { tempBigBuffer = notNull(tempBigBuffer()); } - log.debug(receivedBuffer, tempBigBuffer, "Put received buffer:[%s] to temp big buffer:[%s]"::formatted); + log.debug( + remoteAddress, receivedBuffer, tempBigBuffer, + "[%s] Put received buffer:[%s] to temp big buffer:[%s]"::formatted); + bufferToRead = BufferUtils.putToAndFlip(tempBigBuffer, receivedBuffer); } // if we have some pending data we need to append the received buffer to the pending buffer @@ -134,21 +143,26 @@ protected int readPackets(ByteBuffer receivedBuffer, ByteBuffer pendingBuffer) { else if (waitedBytes > 0) { if (pendingBuffer.remaining() < receivedBuffer.remaining()) { log.debug( + remoteAddress, pendingBuffer, receivedBuffer, - "Pending buffer:[%s] is too small to append received buffer:[%s], allocate new temp bug buffer for this"::formatted); + "[%s] Pending buffer:[%s] is too small to append received buffer:[%s], allocate new temp bug buffer for this"::formatted); allocTempBigBuffers(pendingBuffer.flip(), pendingBuffer.capacity()); - log.debug(pendingBuffer, "Clear pending buffer:[%s]"::formatted); + log.debug(remoteAddress, pendingBuffer, "[%s] Clear pending buffer:[%s]"::formatted); pendingBuffer.clear(); tempBigBuffer = notNull(tempBigBuffer()); - log.debug(receivedBuffer, tempBigBuffer, "Put received buffer:[%s] to temp big buffer:[%s]"::formatted); + log.debug( + remoteAddress, receivedBuffer, tempBigBuffer, + "[%s] Put received buffer:[%s] to temp big buffer:[%s]"::formatted); bufferToRead = BufferUtils.putToAndFlip(tempBigBuffer, receivedBuffer); } else { - log.debug(receivedBuffer, pendingBuffer, "Put received buffer:[%s] to pending buffer:[%s]"::formatted); + log.debug( + remoteAddress, receivedBuffer, pendingBuffer, + "[%s] Put received buffer:[%s] to pending buffer:[%s]"::formatted); bufferToRead = BufferUtils.putToAndFlip(pendingBuffer, receivedBuffer); } } @@ -162,11 +176,13 @@ else if (waitedBytes > 0) { bufferToRead.position(endPosition); int positionBeforeRead = endPosition; - int alreadyReadBytes = bufferToRead.position() - endPosition; int packetFullLength = readFullPacketLength(bufferToRead); + int alreadyReadBytes = bufferToRead.position() - endPosition; int packetDataLength = calculatePacketDataLength(packetFullLength, alreadyReadBytes, bufferToRead); - log.debug(positionBeforeRead, packetFullLength, "Found next packet from position:[%s] with length:[%s] "::formatted); + log.debug( + remoteAddress, positionBeforeRead, packetFullLength, + "[%s] Found next packet from position:[%s] with length:[%s] "::formatted); // calculate position of the end of next packet endPosition += packetFullLength; @@ -180,7 +196,9 @@ else if (waitedBytes > 0) { if (bufferToRead == receivedBuffer) { if (packetFullLength <= pendingBuffer.capacity()) { pendingBuffer.put(receivedBuffer); - log.debug(pendingBuffer, "Put pending data form received buffer to pending buffer:[%s]"::formatted); + log.debug( + remoteAddress, pendingBuffer, + "[%s] Put pending data form received buffer to pending buffer:[%s]"::formatted); } else { allocTempBigBuffers(receivedBuffer, packetFullLength); } @@ -189,10 +207,10 @@ else if (waitedBytes > 0) { else if (bufferToRead == pendingBuffer) { if (packetFullLength <= pendingBuffer.capacity()) { pendingBuffer.compact(); - log.debug(pendingBuffer, "Compact pending buffer:[%s]"::formatted); + log.debug(remoteAddress, pendingBuffer, "[%s] Compact pending buffer:[%s]"::formatted); } else { allocTempBigBuffers(pendingBuffer, packetFullLength); - log.debug(pendingBuffer, "Clear pending buffer:[%s]"::formatted); + log.debug(remoteAddress, pendingBuffer, "[%s] Clear pending buffer:[%s]"::formatted); pendingBuffer.clear(); } @@ -200,7 +218,9 @@ else if (bufferToRead == pendingBuffer) { // if not yet read data is less than pending buffer, then we can switch to use the pending buffer if (Math.max(packetFullLength, tempBigBuffer.remaining()) <= pendingBuffer.capacity()) { pendingBuffer.clear().put(tempBigBuffer); - log.debug(pendingBuffer, "Moved pending data from temp big buffer to pending buffer:[%s]"::formatted); + log.debug( + remoteAddress, pendingBuffer, + "[%s] Moved pending data from temp big buffer to pending buffer:[%s]"::formatted); freeTempBigBuffers(); } // if a new packet is bigger than current temp big buffer @@ -210,14 +230,15 @@ else if (packetFullLength > tempBigBuffer.capacity()) { // or just compact this current temp big buffer else { tempBigBuffer.compact(); - log.debug(tempBigBuffer, "Compact temp big buffer:[%s]]"::formatted); + log.debug(remoteAddress, tempBigBuffer, "[%s] Compact temp big buffer:[%s]]"::formatted); } } log.debug( + remoteAddress, readPackets, connection.remoteAddress(), - ("Read [%s] packets from received buffer of [%s], " + ("[%s] Read [%s] packets from received buffer of [%s], " + "but 1 packet is still waiting for receiving additional data.")::formatted); receivedBuffer.clear(); @@ -231,12 +252,13 @@ else if (packetFullLength > tempBigBuffer.capacity()) { packetDataLength); if (readablePacket != null) { - log.debug(readablePacket, "Created instance of packet to read data:[%s]"::formatted); - readAndHandlePacket(bufferToRead, packetDataLength, readablePacket); - log.debug(readablePacket, "Finished reading data for packet:[%s]"::formatted); + int remainingDataLength = endPosition - bufferToRead.position(); + log.debug(remoteAddress, readablePacket, "[%s] Created instance of packet to read data:[%s]"::formatted); + readAndHandlePacket(bufferToRead, remainingDataLength, readablePacket); + log.debug(remoteAddress, readablePacket, "[%s] Finished reading data for packet:[%s]"::formatted); readPackets++; } else { - log.warning("Cannot create any instance of packet to read data"); + log.warning(remoteAddress, "[%s] Cannot create any instance of packet to read data"::formatted); } bufferToRead.position(endPosition); @@ -245,7 +267,7 @@ else if (packetFullLength > tempBigBuffer.capacity()) { if (bufferToRead.hasRemaining()) { if (bufferToRead == receivedBuffer) { pendingBuffer.put(receivedBuffer); - log.debug("Found not yet read data from receive buffer, will put it to pending buffer."); + log.debug(remoteAddress, "[%s] Found not yet read data from receive buffer, will put it to pending buffer"::formatted); } else { bufferToRead.compact(); } @@ -255,16 +277,17 @@ else if (packetFullLength > tempBigBuffer.capacity()) { freeTempBigBuffers(); } - log.debug(readPackets, connection.remoteAddress(), "Read [%s] packets from received buffer of [%s]"::formatted); + log.debug(remoteAddress, readPackets, "[%s] Read [%s] packets from received buffer"::formatted); receivedBuffer.clear(); return readPackets; } - protected void readAndHandlePacket(ByteBuffer bufferToRead, int packetDataLength, R packetInstance) { - if (packetInstance.read(bufferToRead, packetDataLength)) { + protected void readAndHandlePacket(ByteBuffer bufferToRead, int remainingDataLength, R packetInstance) { + if (packetInstance.read(bufferToRead, remainingDataLength)) { packetHandler.accept(packetInstance); } else { - log.error(packetInstance, "Packet:[%s] was read incorrectly"::formatted); + log.error(remoteAddress(), packetInstance, + "[%s] Packet:[%s] was read incorrectly"::formatted); } } @@ -296,10 +319,12 @@ protected int calculatePacketDataLength(int packetLength, int alreadyReadBytes, protected abstract int readFullPacketLength(ByteBuffer buffer); protected void reAllocTempBigBuffers(ByteBuffer sourceBuffer, int fullPacketLength) { - log.debug(sourceBuffer.capacity(), fullPacketLength, "Resize temp big buffer from:[%s] to:[%s]"::formatted); + log.debug(remoteAddress(), sourceBuffer.capacity(), fullPacketLength, + "[%s] Resize temp big buffer from:[%s] to:[%s]"::formatted); var newTempBuffer = bufferAllocator.takeBuffer(fullPacketLength + readBuffer.capacity()); - log.debug(sourceBuffer, newTempBuffer, "Moved data from old temp big buffer:[%s] to new:[%s]"::formatted); + log.debug(remoteAddress(), sourceBuffer, newTempBuffer, + "[%s] Moved data from old temp big buffer:[%s] to new:[%s]"::formatted); newTempBuffer.put(sourceBuffer); freeTempBigBuffers(); @@ -339,7 +364,7 @@ protected void handleReceivedData(Integer receivedBytes, ByteBuffer readingBuffe return; } - log.debug(receivedBytes, connection.remoteAddress(), "Received [%s] bytes from channel:[%s]"::formatted); + log.debug(remoteAddress(), receivedBytes, "[%s] Received [%s] bytes from channel"::formatted); readingBuffer.flip(); try { readPackets(readingBuffer); @@ -360,7 +385,7 @@ protected void handleReceivedData(Integer receivedBytes, ByteBuffer readingBuffe */ protected void handleFailedReceiving(Throwable exception, ByteBuffer readingBuffer) { if (exception instanceof AsynchronousCloseException) { - log.info(connection.remoteAddress(), "Connection:[%s] was closed"::formatted); + log.info(remoteAddress(), "[%s] Connection was closed"::formatted); } else { log.error(exception); connection.close(); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java index edc809c3..0e3f93ee 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java @@ -32,7 +32,6 @@ public abstract class AbstractNetworkPacketWriter> implements NetworkPacketWriter { - final CompletionHandler writeHandler = new CompletionHandler<>() { @Override @@ -86,6 +85,10 @@ public AbstractNetworkPacketWriter( this.sentPacketHandler = sentPacketHandler; } + protected String remoteAddress() { + return connection.remoteAddress(); + } + @Override public boolean tryToSendNextPacket() { if (connection.closed() || !writing.compareAndSet(false, true)) { @@ -103,8 +106,8 @@ public boolean tryToSendNextPacket() { if (resultBuffer.limit() != 0) { writingBuffer = resultBuffer; - log.debug(connection.remoteAddress(), resultBuffer, - (address, buff) -> "Write to channel:[%] data:\n" + hexDump(buff)); + log.debug(remoteAddress(), resultBuffer, + (address, buff) -> "[%s] Write to channel data:\n" + hexDump(buff)); socketChannel.write(resultBuffer, nextPacket, writeHandler); startedWriting = true; } else { @@ -275,8 +278,8 @@ protected ByteBuffer writeHeader(ByteBuffer buffer, int position, int value, int } return buffer; } catch (IndexOutOfBoundsException ex) { - log.error(position, headerSize, buffer, - "Cannot write header by position:[%s] with header size:[%s] to buffer:[%s]"::formatted); + log.error(remoteAddress(), position, headerSize, buffer, + "[%s] Cannot write header by position:[%s] with header size:[%s] to buffer:[%s]"::formatted); throw ex; } } @@ -315,12 +318,12 @@ protected void handleSuccessfulWritingData(Integer wroteBytes, WritableNetworkPa ByteBuffer writingBuffer = writingBuffer(); if (writingBuffer.remaining() > 0) { - log.debug(writingBuffer, connection.remoteAddress(), - "Buffer was not consumed fully, try to write else [%s] bytes to channel:[%s]"::formatted); + log.debug(remoteAddress(), writingBuffer, + "[%s] Buffer was not consumed fully, try to write else [%s] bytes to channel"::formatted); socketChannel.write(writingBuffer, packet, writeHandler); return; } else { - log.debug(wroteBytes, "Finished writing [%s] bytes"::formatted); + log.debug(remoteAddress(), wroteBytes, "[%s] Finished writing [%s] bytes"::formatted); } sentPacketHandler.accept(packet, true); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java index ca47c5a4..a4357a23 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java @@ -20,10 +20,10 @@ public abstract class AbstractReadableNetworkPacket extends AbstractNetworkPacket implements ReadableNetworkPacket { @Override - public boolean read(ByteBuffer buffer, int expectedLength) { + public boolean read(ByteBuffer buffer, int remainingDataLength) { int oldLimit = buffer.limit(); try { - buffer.limit(buffer.position() + expectedLength); + buffer.limit(buffer.position() + remainingDataLength); readImpl(buffer); return true; } catch (Exception e) { diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadableNetworkPacket.java index 98372a57..71115e89 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/DefaultReadableNetworkPacket.java @@ -6,8 +6,4 @@ public class DefaultReadableNetworkPacket extends AbstractIdBasedReadableNetworkPacket { - @Override - public DefaultReadableNetworkPacket newInstance() { - return new DefaultReadableNetworkPacket(); - } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadableNetworkPacketRegistry.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadableNetworkPacketRegistry.java index af8b0223..3a0cf08a 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadableNetworkPacketRegistry.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/registry/ReadableNetworkPacketRegistry.java @@ -63,11 +63,8 @@ static ReadableNetworkPacketRegistry of(ClassPathScanner scanner) { .stream() .filter(type -> type.getAnnotation(NetworkPacketDescription.class) != null) .collect(ArrayCollectors.>toArray(Class.class)); - - var registry = new IdBasedReadableNetworkPacketRegistry<>(IdBasedReadableNetworkPacket.class); - registry.register(result); - - return registry; + return new IdBasedReadableNetworkPacketRegistry<>(IdBasedReadableNetworkPacket.class) + .register(result); } /** @@ -77,9 +74,8 @@ static ReadableNetworkPacketRegistry of(ClassPathScanner scanner) { static > ReadableNetworkPacketRegistry of( Class type, Class... classes) { - var registry = new IdBasedReadableNetworkPacketRegistry<>(type); - registry.register(classes, classes.length); - return registry; + return new IdBasedReadableNetworkPacketRegistry<>(type) + .register(classes, classes.length); } /** @@ -88,11 +84,8 @@ static > ReadableNetworkPacketRegistry static > ReadableNetworkPacketRegistry of( Class type, Array> classes) { - - var registry = new IdBasedReadableNetworkPacketRegistry<>(type); - registry.register(classes); - - return registry; + return new IdBasedReadableNetworkPacketRegistry<>(type) + .register(classes); } /** diff --git a/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java index be347c17..2091e2b3 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java @@ -15,10 +15,13 @@ import java.util.stream.IntStream; import javasabr.rlib.common.util.ObjectUtils; import javasabr.rlib.common.util.StringUtils; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.annotation.NetworkPacketDescription; import javasabr.rlib.network.impl.DefaultBufferAllocator; import javasabr.rlib.network.impl.DefaultConnection; import javasabr.rlib.network.packet.MarkerNetworkPacket; +import javasabr.rlib.network.packet.impl.AbstractNetworkPacketReader; import javasabr.rlib.network.packet.impl.DefaultReadableNetworkPacket; import javasabr.rlib.network.packet.impl.DefaultWritableNetworkPacket; import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; @@ -27,7 +30,6 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.SneakyThrows; -import lombok.ToString; import org.jspecify.annotations.Nullable; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -59,7 +61,6 @@ protected void writeImpl(ByteBuffer buffer) { @NetworkPacketDescription(id = 2) class RequestServerTime extends DefaultWritableNetworkPacket implements MarkerNetworkPacket {} - @ToString @RequiredArgsConstructor @NetworkPacketDescription(id = 3) class ResponseEchoMessage extends DefaultReadableNetworkPacket { @@ -72,9 +73,13 @@ class ResponseEchoMessage extends DefaultReadableNetworkPacket { protected void readImpl(ByteBuffer buffer) { message = readString(buffer, Integer.MAX_VALUE); } + + @Override + public String toString() { + return "Message:[" + message + "]"; + } } - @ToString @NetworkPacketDescription(id = 4) class ResponseServerTime extends DefaultReadableNetworkPacket { @@ -87,13 +92,17 @@ protected void readImpl(ByteBuffer buffer) { super.readImpl(buffer); localDateTime = LocalDateTime.ofEpochSecond(readLong(buffer), 0, ZoneOffset.ofTotalSeconds(readInt(buffer))); } + + @Override + public String toString() { + return "ResponseServerTime"; + } } } // server packets interface ServerPackets { - @ToString @NetworkPacketDescription(id = 1) class RequestEchoMessage extends DefaultReadableNetworkPacket { @@ -104,11 +113,21 @@ protected void readImpl(ByteBuffer buffer) { super.readImpl(buffer); message = readString(buffer, Integer.MAX_VALUE); } + + @Override + public String toString() { + return "Message:[" + message + "]"; + } } - @ToString @NetworkPacketDescription(id = 2) - class RequestServerTime extends DefaultReadableNetworkPacket implements MarkerNetworkPacket {} + class RequestServerTime extends DefaultReadableNetworkPacket implements MarkerNetworkPacket { + + @Override + public String toString() { + return "RequestServerTime"; + } + } @RequiredArgsConstructor @NetworkPacketDescription(id = 3) @@ -139,6 +158,9 @@ protected void writeImpl(ByteBuffer buffer) { @Test @SneakyThrows void echoNetworkTest() { + LoggerManager.enable(DefaultNetworkTest.class, LoggerLevel.DEBUG); + LoggerManager.enable(DefaultNetworkTest.class, LoggerLevel.INFO); + LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.DEBUG); ReadableNetworkPacketRegistry serverPackets = ReadableNetworkPacketRegistry.of( DefaultReadableNetworkPacket.class, diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java index b14782df..e8fa2509 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java @@ -9,16 +9,23 @@ import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.IntStream; import javasabr.rlib.common.util.ObjectUtils; import javasabr.rlib.common.util.StringUtils; +import javasabr.rlib.common.util.ThreadUtils; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.ServerNetworkConfig.SimpleServerNetworkConfig; import javasabr.rlib.network.client.ClientNetwork; import javasabr.rlib.network.impl.DefaultBufferAllocator; import javasabr.rlib.network.impl.StringDataConnection; +import javasabr.rlib.network.packet.impl.AbstractNetworkPacketReader; import javasabr.rlib.network.packet.impl.StringReadablePacket; import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; import javasabr.rlib.network.server.ServerNetwork; @@ -39,35 +46,49 @@ public class StringNetworkTest extends BaseNetworkTest { @Test @SneakyThrows void echoNetworkTest() { + //LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); + LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.INFO); + //LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.DEBUG); ServerNetwork serverNetwork = NetworkFactory.stringDataServerNetwork(); InetSocketAddress serverAddress = serverNetwork.start(); - var counter = new CountDownLatch(90); + log.info(serverAddress, "Server address:[%s]"::formatted); + + var counter = new CountDownLatch(190); serverNetwork .accepted() .flatMap(Connection::receivedEvents) .subscribe(event -> { String message = event.packet().data(); - log.info(message, "Received from client:[%s]"::formatted); + //log.info(message, "Received from client:[%s]"::formatted); event.connection().send(new StringWritableNetworkPacket("Echo: " + message)); }); + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); var clientNetwork = NetworkFactory.stringDataClientNetwork(); clientNetwork .connectReactive(serverAddress) .doOnNext(connection -> IntStream - .range(10, 100) - .forEach(length -> connection.send(new StringWritableNetworkPacket(StringUtils.generate(length))))) + .range(10, 200) + .forEach(length -> { + var packet = new StringWritableNetworkPacket(StringUtils.generate(length)); + int delay = ThreadLocalRandom + .current() + .nextInt(50); + connection.send(packet); + //executor.schedule(() -> connection.send(packet), delay, TimeUnit.MILLISECONDS); + })) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { - log.info(event.packet().data(), "Received from server:[%s]"::formatted); + //log.info(event.packet().data(), "Received from server:[%s]"::formatted); counter.countDown(); + log.info(counter.getCount(), "Still wait for:[%s]"::formatted); }); Assertions.assertTrue( - counter.await(10000, TimeUnit.MILLISECONDS), + counter.await(10000, TimeUnit.MINUTES), "Still wait for " + counter.getCount() + " packets..."); clientNetwork.shutdown(); From 3b91cb14cb64ae3942cbd45d86d4a227f86cffa6 Mon Sep 17 00:00:00 2001 From: javasabr Date: Fri, 3 Oct 2025 20:57:01 +0200 Subject: [PATCH 05/15] continue working on network and fix dequeues --- .../packet/impl/StringReadablePacket.java | 2 +- .../rlib/network/StringNetworkTest.java | 50 +++++++++++++------ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java index ed7c7aad..a896ef20 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java @@ -15,7 +15,7 @@ @FieldDefaults(level = AccessLevel.PROTECTED) public class StringReadablePacket extends AbstractReadableNetworkPacket { - public static final int MAX_LENGTH = 10_000; + public static final int MAX_LENGTH = 100_000; @Nullable volatile String data; diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java index e8fa2509..3bc35859 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java @@ -46,8 +46,8 @@ public class StringNetworkTest extends BaseNetworkTest { @Test @SneakyThrows void echoNetworkTest() { - //LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); - LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.INFO); + LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); + //LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.INFO); //LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.DEBUG); ServerNetwork serverNetwork = NetworkFactory.stringDataServerNetwork(); @@ -62,7 +62,7 @@ void echoNetworkTest() { .flatMap(Connection::receivedEvents) .subscribe(event -> { String message = event.packet().data(); - //log.info(message, "Received from client:[%s]"::formatted); + log.info(message, "Received from client:[%s]"::formatted); event.connection().send(new StringWritableNetworkPacket("Echo: " + message)); }); @@ -77,12 +77,11 @@ void echoNetworkTest() { int delay = ThreadLocalRandom .current() .nextInt(50); - connection.send(packet); - //executor.schedule(() -> connection.send(packet), delay, TimeUnit.MILLISECONDS); + executor.schedule(() -> connection.send(packet), delay, TimeUnit.MILLISECONDS); })) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { - //log.info(event.packet().data(), "Received from server:[%s]"::formatted); + log.info(event.packet().data(), "Received from server:[%s]"::formatted); counter.countDown(); log.info(counter.getCount(), "Still wait for:[%s]"::formatted); }); @@ -93,6 +92,7 @@ void echoNetworkTest() { clientNetwork.shutdown(); serverNetwork.shutdown(); + executor.shutdown(); } @Test @@ -157,8 +157,10 @@ public ByteBuffer takeBuffer(int bufferSize) { @Test void shouldReceiveManyPacketsFromSmallToBigSize() { - int packetCount = 200; - try (TestNetwork testNetwork = buildStringNetwork()) { + //LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); + int packetCount = 2000; + try (TestNetwork testNetwork = buildStringNetwork(); + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1)) { int bufferSize = testNetwork.serverNetworkConfig.readBufferSize(); var random = ThreadLocalRandom.current(); @@ -167,6 +169,8 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { var pendingPacketsOnServer = serverToClient .receivedPackets() + .doOnNext(packet -> + log.info(packet.data().length(), "Received [%s] symbols from client"::formatted)) .buffer(packetCount); var messages = IntStream @@ -176,8 +180,15 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { return StringUtils.generate(length); }) .peek(message -> { - log.info(message.length(), "Send [%s] symbols to server"::formatted); - clientToServer.send(new StringWritableNetworkPacket(message)); + var packet = new StringWritableNetworkPacket(message); + int delay = ThreadLocalRandom + .current() + .nextInt(15); + executor.schedule( + () -> { + clientToServer.send(packet); + log.info(message.length(), "Send [%s] symbols to server"::formatted); + }, delay, TimeUnit.MILLISECONDS); }) .toList(); @@ -202,10 +213,12 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { @Test void shouldSendBiggerPacketThanWriteBuffer() { + LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); int packetCount = 10_000; - try (TestNetwork testNetwork = buildStringNetwork()) { + try (TestNetwork testNetwork = buildStringNetwork(); + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1)) { int bufferSize = testNetwork.clientNetworkConfig.writeBufferSize(); var random = ThreadLocalRandom.current(); @@ -214,19 +227,26 @@ void shouldSendBiggerPacketThanWriteBuffer() { var pendingPacketsOnServer = serverToClient .receivedPackets() + .doOnNext(packet -> + log.info(packet.data().length(), "Received [%s] symbols from client"::formatted)) .buffer(packetCount); List messages = IntStream .range(0, packetCount) .mapToObj(value -> { - var length = random.nextBoolean() ? random.nextInt(bufferSize, bufferSize * 10) : random.nextInt(0, 200); - return StringUtils.generate(length); }) .peek(message -> { - log.info(message.length(), "Send [%s] symbols to server"::formatted); - clientToServer.send(new StringWritableNetworkPacket(message)); + var packet = new StringWritableNetworkPacket(message); + int delay = ThreadLocalRandom + .current() + .nextInt(15); + executor.schedule( + () -> { + clientToServer.send(packet); + log.info(message.length(), "Send [%s] symbols to server"::formatted); + }, delay, TimeUnit.MILLISECONDS); }) .toList(); From b57c56f3c478a6cef08cfb578630c1fae1db9bb0 Mon Sep 17 00:00:00 2001 From: javasabr Date: Fri, 3 Oct 2025 20:59:21 +0200 Subject: [PATCH 06/15] continue working on network and fix dequeues --- .../javasabr/rlib/network/DefaultNetworkTest.java | 9 +++------ .../javasabr/rlib/network/StringNetworkTest.java | 12 ++++-------- ...LNetworkTest.java => StringSslNetworkTest.java} | 14 +++++++------- 3 files changed, 14 insertions(+), 21 deletions(-) rename rlib-network/src/test/java/javasabr/rlib/network/{StringSSLNetworkTest.java => StringSslNetworkTest.java} (96%) diff --git a/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java index 2091e2b3..43d86534 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/DefaultNetworkTest.java @@ -15,13 +15,10 @@ import java.util.stream.IntStream; import javasabr.rlib.common.util.ObjectUtils; import javasabr.rlib.common.util.StringUtils; -import javasabr.rlib.logger.api.LoggerLevel; -import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.annotation.NetworkPacketDescription; import javasabr.rlib.network.impl.DefaultBufferAllocator; import javasabr.rlib.network.impl.DefaultConnection; import javasabr.rlib.network.packet.MarkerNetworkPacket; -import javasabr.rlib.network.packet.impl.AbstractNetworkPacketReader; import javasabr.rlib.network.packet.impl.DefaultReadableNetworkPacket; import javasabr.rlib.network.packet.impl.DefaultWritableNetworkPacket; import javasabr.rlib.network.packet.registry.ReadableNetworkPacketRegistry; @@ -158,9 +155,9 @@ protected void writeImpl(ByteBuffer buffer) { @Test @SneakyThrows void echoNetworkTest() { - LoggerManager.enable(DefaultNetworkTest.class, LoggerLevel.DEBUG); - LoggerManager.enable(DefaultNetworkTest.class, LoggerLevel.INFO); - LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.DEBUG); + //LoggerManager.enable(DefaultNetworkTest.class, LoggerLevel.DEBUG); + //LoggerManager.enable(DefaultNetworkTest.class, LoggerLevel.INFO); + //LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.DEBUG); ReadableNetworkPacketRegistry serverPackets = ReadableNetworkPacketRegistry.of( DefaultReadableNetworkPacket.class, diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java index 3bc35859..9378b0d5 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringNetworkTest.java @@ -9,7 +9,6 @@ import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadLocalRandom; @@ -18,14 +17,10 @@ import java.util.stream.IntStream; import javasabr.rlib.common.util.ObjectUtils; import javasabr.rlib.common.util.StringUtils; -import javasabr.rlib.common.util.ThreadUtils; -import javasabr.rlib.logger.api.LoggerLevel; -import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.ServerNetworkConfig.SimpleServerNetworkConfig; import javasabr.rlib.network.client.ClientNetwork; import javasabr.rlib.network.impl.DefaultBufferAllocator; import javasabr.rlib.network.impl.StringDataConnection; -import javasabr.rlib.network.packet.impl.AbstractNetworkPacketReader; import javasabr.rlib.network.packet.impl.StringReadablePacket; import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; import javasabr.rlib.network.server.ServerNetwork; @@ -46,7 +41,7 @@ public class StringNetworkTest extends BaseNetworkTest { @Test @SneakyThrows void echoNetworkTest() { - LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); + //LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); //LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.INFO); //LoggerManager.enable(AbstractNetworkPacketReader.class, LoggerLevel.DEBUG); @@ -158,7 +153,9 @@ public ByteBuffer takeBuffer(int bufferSize) { @Test void shouldReceiveManyPacketsFromSmallToBigSize() { //LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); + int packetCount = 2000; + try (TestNetwork testNetwork = buildStringNetwork(); ScheduledExecutorService executor = Executors.newScheduledThreadPool(1)) { int bufferSize = testNetwork.serverNetworkConfig.readBufferSize(); @@ -213,7 +210,7 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { @Test void shouldSendBiggerPacketThanWriteBuffer() { - LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); + //LoggerManager.enable(StringNetworkTest.class, LoggerLevel.INFO); int packetCount = 10_000; @@ -272,7 +269,6 @@ void shouldSendBiggerPacketThanWriteBuffer() { @Test @SneakyThrows void testServerWithMultiplyClients() { - //LoggerManager.enable(AbstractPacketWriter.class, LoggerLevel.DEBUG); var serverConfig = SimpleServerNetworkConfig diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java similarity index 96% rename from rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java rename to rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java index 62c9bb1c..23c6bed6 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringSSLNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java @@ -42,15 +42,15 @@ * * @author JavaSaBr */ -public class StringSSLNetworkTest extends BaseNetworkTest { +public class StringSslNetworkTest extends BaseNetworkTest { - private static final Logger LOGGER = LoggerManager.getLogger(StringSSLNetworkTest.class); + private static final Logger LOGGER = LoggerManager.getLogger(StringSslNetworkTest.class); @Test @SneakyThrows void certificatesTest() { - InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); SSLContext clientSSLContext = NetworkUtils.createAllTrustedClientSslContext(); @@ -80,7 +80,7 @@ void certificatesTest() { @SneakyThrows void serverSSLNetworkTest() { - InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); ServerNetwork serverNetwork = NetworkFactory.stringDataSslServerNetwork( @@ -141,7 +141,7 @@ void clientSSLNetworkTest() { //LoggerManager.enable(AbstractSSLPacketWriter.class, LoggerLevel.DEBUG); //LoggerManager.enable(AbstractSSLPacketReader.class, LoggerLevel.DEBUG); - InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); int serverPort = NetworkUtils.getAvailablePort(1000); @@ -217,7 +217,7 @@ void echoNetworkTest() { //LoggerManager.enable(AbstractSSLPacketWriter.class, LoggerLevel.DEBUG); //LoggerManager.enable(AbstractSSLPacketReader.class, LoggerLevel.DEBUG); - InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); ServerNetwork serverNetwork = NetworkFactory.stringDataSslServerNetwork( @@ -278,7 +278,7 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { LoggerManager.enable(AbstractSslNetworkPacketWriter.class, LoggerLevel.DEBUG); LoggerManager.enable(AbstractSslNetworkPacketReader.class, LoggerLevel.DEBUG); - InputStream keystoreFile = StringSSLNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); SSLContext clientSSLContext = NetworkUtils.createAllTrustedClientSslContext(); From 8fca63af32458395f503823234796cd616b629e1 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sat, 4 Oct 2025 11:19:10 +0200 Subject: [PATCH 07/15] upgrade gradle structure and introduce load tests --- build.gradle | 85 +------------- buildSrc/build.gradle | 8 ++ buildSrc/settings.gradle | 3 + .../src/main/groovy/configure-jacoco.gradle | 12 ++ .../src/main/groovy/configure-java.gradle | 108 ++++++++++++++++++ .../main/groovy}/configure-publishing.gradle | 4 +- rlib-classpath/build.gradle | 5 +- rlib-collections/build.gradle | 5 +- rlib-common/build.gradle | 5 +- rlib-compiler/build.gradle | 5 +- rlib-concurrent/build.gradle | 5 +- rlib-functions/build.gradle | 5 +- rlib-fx/build.gradle | 4 +- rlib-geometry/build.gradle | 5 +- rlib-io/build.gradle | 5 +- rlib-logger-api/build.gradle | 5 +- rlib-logger-impl/build.gradle | 5 +- rlib-logger-slf4j/build.gradle | 5 +- rlib-mail/build.gradle | 5 +- rlib-network/build.gradle | 6 +- .../rlib/network/StringNetworkLoadTest.java | 97 ++++++++++++++++ .../impl/AbstractNetworkPacketReader.java | 6 +- .../impl/AbstractSslNetworkPacketReader.java | 34 +----- .../impl/StringWritableNetworkPacket.java | 4 + .../rlib/network/StringSslNetworkTest.java | 70 +++++++----- rlib-plugin-system/build.gradle | 5 +- rlib-reference/build.gradle | 5 +- rlib-reusable/build.gradle | 5 +- rlib-testcontainers/build.gradle | 5 +- test-coverage/build.gradle | 4 +- 30 files changed, 361 insertions(+), 164 deletions(-) create mode 100644 buildSrc/build.gradle create mode 100644 buildSrc/settings.gradle create mode 100644 buildSrc/src/main/groovy/configure-jacoco.gradle create mode 100644 buildSrc/src/main/groovy/configure-java.gradle rename {gradle => buildSrc/src/main/groovy}/configure-publishing.gradle (95%) create mode 100644 rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java diff --git a/build.gradle b/build.gradle index 7a7213bc..29f24efd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,93 +1,10 @@ rootProject.version = "10.0.alpha1" group = 'javasabr.rlib' -subprojects { +allprojects { repositories { mavenCentral() } - - apply plugin: "java-library" - apply plugin: "java-test-fixtures" - apply plugin: "jacoco" - - java { - toolchain { - languageVersion = JavaLanguageVersion.of(21) - } - } - - javadoc { - failOnError = false - } - - test { - useJUnitPlatform() - failOnNoDiscoveredTests = false - } - - dependencies { - compileOnly libs.jspecify - compileOnly libs.lombok - annotationProcessor libs.lombok - - testImplementation libs.junit.api - testImplementation libs.junit.jupiter.params - testCompileOnly libs.lombok - testCompileOnly libs.jspecify - testRuntimeOnly libs.junit.engine - testRuntimeOnly libs.junit.platform.launcher - testAnnotationProcessor libs.lombok - } - - tasks.withType(JavaCompile).configureEach { - options.encoding = "UTF-8" - } - - tasks.withType(Javadoc).configureEach { - options.encoding = "UTF-8" - } - - tasks.register("sourcesJar", Jar) { - dependsOn "classes" - group "build" - archiveClassifier = "sources" - archiveBaseName = jar.archiveBaseName - from sourceSets.main.allSource - } - - tasks.register("javadocJar", Jar) { - dependsOn "javadoc" - group "build" - archiveClassifier = "javadoc" - archiveBaseName = jar.archiveBaseName - from sourceSets.main.allSource - } - - configurations { - testArtifacts.extendsFrom testRuntime - } - - tasks.register('testJar', Jar) { - archiveClassifier = "test" - from sourceSets.test.output - } - - artifacts { - testArtifacts testJar - } - - tasks.withType(Test).configureEach { - maxParallelForks = Runtime.runtime.availableProcessors() - } - - jacocoTestReport { - dependsOn test - reports { - xml.required = false - csv.required = false - html.outputLocation = layout.buildDirectory.dir('jacocoHtml') - } - } } wrapper { diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 00000000..3a85dcfe --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,8 @@ +plugins { + id 'groovy-gradle-plugin' +} + +repositories { + mavenCentral() + gradlePluginPortal() +} \ No newline at end of file diff --git a/buildSrc/settings.gradle b/buildSrc/settings.gradle new file mode 100644 index 00000000..717dd794 --- /dev/null +++ b/buildSrc/settings.gradle @@ -0,0 +1,3 @@ +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") + +rootProject.name = 'rlib-build-configuration' \ No newline at end of file diff --git a/buildSrc/src/main/groovy/configure-jacoco.gradle b/buildSrc/src/main/groovy/configure-jacoco.gradle new file mode 100644 index 00000000..3e77f6c3 --- /dev/null +++ b/buildSrc/src/main/groovy/configure-jacoco.gradle @@ -0,0 +1,12 @@ +plugins { + id "jacoco" +} + +jacocoTestReport { + dependsOn test + reports { + xml.required = false + csv.required = false + html.outputLocation = layout.buildDirectory.dir('jacocoHtml') + } +} diff --git a/buildSrc/src/main/groovy/configure-java.gradle b/buildSrc/src/main/groovy/configure-java.gradle new file mode 100644 index 00000000..d076ad57 --- /dev/null +++ b/buildSrc/src/main/groovy/configure-java.gradle @@ -0,0 +1,108 @@ +plugins { + id("java-library") + id("java-test-fixtures") + id("configure-jacoco") +} + +repositories { + mavenCentral() +} + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } +} + +sourceSets { + loadTest { + compileClasspath += main.output + compileClasspath += main.compileClasspath + compileClasspath += test.compileClasspath + runtimeClasspath += main.output + runtimeClasspath += main.compileClasspath + runtimeClasspath += test.compileClasspath + java { + srcDirs = ["src/loadTest/java"] + } + } +} + +javadoc { + failOnError = false +} + +test { + useJUnitPlatform() + failOnNoDiscoveredTests = false +} + +tasks.register("loadTest", Test) { + group("verification") + useJUnitPlatform() + failOnNoDiscoveredTests = false + testClassesDirs = sourceSets.loadTest.output.classesDirs + classpath = sourceSets.loadTest.runtimeClasspath +} + +dependencies { + compileOnly libs.jspecify + compileOnly libs.lombok + annotationProcessor libs.lombok + + testImplementation libs.junit.api + testImplementation libs.junit.jupiter.params + + testCompileOnly libs.lombok + testCompileOnly libs.jspecify + testRuntimeOnly libs.junit.engine + testRuntimeOnly libs.junit.platform.launcher + testAnnotationProcessor libs.lombok + + loadTestCompileOnly libs.lombok + loadTestCompileOnly libs.jspecify + loadTestRuntimeOnly libs.junit.engine + loadTestRuntimeOnly libs.junit.platform.launcher + loadTestAnnotationProcessor libs.lombok +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = "UTF-8" +} + +tasks.withType(Javadoc).configureEach { + options.encoding = "UTF-8" +} + +tasks.register("sourcesJar", Jar) { + dependsOn "classes" + group "build" + archiveClassifier = "sources" + archiveBaseName = jar.archiveBaseName + from sourceSets.main.allSource +} + +tasks.register("javadocJar", Jar) { + dependsOn "javadoc" + group "build" + archiveClassifier = "javadoc" + archiveBaseName = jar.archiveBaseName + from sourceSets.main.allSource +} + +configurations { + testArtifacts.extendsFrom testRuntime +} + +tasks.register('testJar', Jar) { + archiveClassifier = "test" + from sourceSets.test.output +} + +artifacts { + testArtifacts testJar +} + +tasks.withType(Test).configureEach { + maxParallelForks = Runtime.runtime.availableProcessors() +} diff --git a/gradle/configure-publishing.gradle b/buildSrc/src/main/groovy/configure-publishing.gradle similarity index 95% rename from gradle/configure-publishing.gradle rename to buildSrc/src/main/groovy/configure-publishing.gradle index 833482b0..7f3ff3cc 100644 --- a/gradle/configure-publishing.gradle +++ b/buildSrc/src/main/groovy/configure-publishing.gradle @@ -1,4 +1,6 @@ -apply plugin: "maven-publish" +plugins { + id("maven-publish") +} publishing { repositories { diff --git a/rlib-classpath/build.gradle b/rlib-classpath/build.gradle index 31ec1664..c2953f2c 100644 --- a/rlib-classpath/build.gradle +++ b/rlib-classpath/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon diff --git a/rlib-collections/build.gradle b/rlib-collections/build.gradle index 64359f8e..e5e445f0 100644 --- a/rlib-collections/build.gradle +++ b/rlib-collections/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon diff --git a/rlib-common/build.gradle b/rlib-common/build.gradle index 996db654..a70affdd 100644 --- a/rlib-common/build.gradle +++ b/rlib-common/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibLoggerApi diff --git a/rlib-compiler/build.gradle b/rlib-compiler/build.gradle index 31ec1664..c2953f2c 100644 --- a/rlib-compiler/build.gradle +++ b/rlib-compiler/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon diff --git a/rlib-concurrent/build.gradle b/rlib-concurrent/build.gradle index d065f972..a8b1acac 100644 --- a/rlib-concurrent/build.gradle +++ b/rlib-concurrent/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCollections diff --git a/rlib-functions/build.gradle b/rlib-functions/build.gradle index 450a0ed2..4c5cb706 100644 --- a/rlib-functions/build.gradle +++ b/rlib-functions/build.gradle @@ -1 +1,4 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} diff --git a/rlib-fx/build.gradle b/rlib-fx/build.gradle index 10ac9960..6b1ce95c 100644 --- a/rlib-fx/build.gradle +++ b/rlib-fx/build.gradle @@ -1,9 +1,9 @@ plugins { + id("configure-java") id 'org.openjfx.javafxplugin' version '0.1.0' + id("configure-publishing") } -apply from: "$rootDir/gradle/configure-publishing.gradle" - dependencies { api projects.rlibCommon api projects.rlibReference diff --git a/rlib-geometry/build.gradle b/rlib-geometry/build.gradle index 7515479c..5f62cda3 100644 --- a/rlib-geometry/build.gradle +++ b/rlib-geometry/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon diff --git a/rlib-io/build.gradle b/rlib-io/build.gradle index 2f86818a..499f1cee 100644 --- a/rlib-io/build.gradle +++ b/rlib-io/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon diff --git a/rlib-logger-api/build.gradle b/rlib-logger-api/build.gradle index 4838f74a..4c5cb706 100644 --- a/rlib-logger-api/build.gradle +++ b/rlib-logger-api/build.gradle @@ -1 +1,4 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" \ No newline at end of file +plugins { + id("configure-java") + id("configure-publishing") +} diff --git a/rlib-logger-impl/build.gradle b/rlib-logger-impl/build.gradle index 60dc1360..99773b26 100644 --- a/rlib-logger-impl/build.gradle +++ b/rlib-logger-impl/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon diff --git a/rlib-logger-slf4j/build.gradle b/rlib-logger-slf4j/build.gradle index c8eee225..08ad7c5e 100644 --- a/rlib-logger-slf4j/build.gradle +++ b/rlib-logger-slf4j/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibLoggerApi diff --git a/rlib-mail/build.gradle b/rlib-mail/build.gradle index 66d714f1..814906a3 100644 --- a/rlib-mail/build.gradle +++ b/rlib-mail/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon diff --git a/rlib-network/build.gradle b/rlib-network/build.gradle index 0a04377b..8ddfd5d0 100644 --- a/rlib-network/build.gradle +++ b/rlib-network/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon @@ -7,4 +10,5 @@ dependencies { api projects.rlibReusable api libs.project.reactor.core testRuntimeOnly projects.rlibLoggerImpl + loadTestRuntimeOnly projects.rlibLoggerImpl } diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java new file mode 100644 index 00000000..04e11f00 --- /dev/null +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java @@ -0,0 +1,97 @@ +package javasabr.rlib.network; + +import static javasabr.rlib.network.ServerNetworkConfig.DEFAULT_SERVER; + +import java.net.InetSocketAddress; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; +import javasabr.rlib.common.util.StringUtils; +import javasabr.rlib.network.ServerNetworkConfig.SimpleServerNetworkConfig; +import javasabr.rlib.network.client.ClientNetwork; +import javasabr.rlib.network.impl.DefaultBufferAllocator; +import javasabr.rlib.network.impl.StringDataConnection; +import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; +import javasabr.rlib.network.server.ServerNetwork; +import lombok.CustomLog; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Flux; + +@CustomLog +public class StringNetworkLoadTest { + + private static class TestClient { + + } + + @Test + @SneakyThrows + void testServerWithMultiplyClients() { + //LoggerManager.enable(AbstractPacketWriter.class, LoggerLevel.DEBUG); + + var serverConfig = SimpleServerNetworkConfig + .builder() + .threadGroupSize(10) + .build(); + + var serverAllocator = new DefaultBufferAllocator(serverConfig); + var clientAllocator = new DefaultBufferAllocator(NetworkConfig.DEFAULT_CLIENT); + + int clientCount = 100; + int packetsPerClient = 100; + int minMessageLength = 10; + int maxMessageLength = (int) (DEFAULT_SERVER.readBufferSize() * 1.5); + + var counter = new CountDownLatch(clientCount * packetsPerClient); + var sentPacketsToServer = new AtomicInteger(); + var receivedPacketsOnServer = new AtomicInteger(); + var receivedPacketsOnClients = new AtomicInteger(); + + ServerNetwork serverNetwork = NetworkFactory.stringDataServerNetwork(serverConfig, serverAllocator); + InetSocketAddress serverAddress = serverNetwork.start(); + + serverNetwork + .accepted() + .flatMap(Connection::receivedEvents) + .doOnNext(event -> receivedPacketsOnServer.incrementAndGet()) + .subscribe(event -> event.connection().send(newMessage(minMessageLength, maxMessageLength))); + + Flux + .fromStream(IntStream + .range(0, clientCount) + .mapToObj(value -> NetworkFactory.stringDataClientNetwork(NetworkConfig.DEFAULT_CLIENT, clientAllocator))) + .doOnDiscard(ClientNetwork.class, Network::shutdown) + .flatMap(client -> client.connectReactive(serverAddress)) + .flatMap(connection -> { + + var receivedEvents = connection.receivedEvents(); + + for (int i = 0; i < packetsPerClient; i++) { + connection.send(newMessage(minMessageLength, maxMessageLength)); + sentPacketsToServer.incrementAndGet(); + } + + return receivedEvents; + }) + .subscribe(event -> { + receivedPacketsOnClients.incrementAndGet(); + counter.countDown(); + }); + + Assertions + .assertTrue( + counter.await(10000, TimeUnit.MILLISECONDS), + "Still wait for " + counter.getCount() + " packets... " + "Sent packets to server: " + sentPacketsToServer + + ", " + "Received packets on server: " + receivedPacketsOnServer + ", " + "Received packets on clients: " + + receivedPacketsOnClients); + + serverNetwork.shutdown(); + } + + private static StringWritableNetworkPacket newMessage(int minMessageLength, int maxMessageLength) { + return new StringWritableNetworkPacket(StringUtils.generate(minMessageLength, maxMessageLength)); + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java index c6abe8e3..2677c86c 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java @@ -34,7 +34,11 @@ public abstract class AbstractNetworkPacketReader the readable packet's type. - * @param the connection's type. + * @author JavaSaBr */ @CustomLog @FieldDefaults(level = AccessLevel.PROTECTED) @@ -89,32 +88,26 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); while (handshakeStatus != HandshakeStatus.FINISHED && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) { log.debug(handshakeStatus, "Do handshake with status:[%s] "::formatted); - SSLEngineResult result; - switch (handshakeStatus) { case NEED_UNWRAP: { if (receivedBytes == -1) { if (sslEngine.isInboundDone() && sslEngine.isOutboundDone()) { return SKIP_READ_PACKETS; } - try { sslEngine.closeInbound(); } catch (SSLException e) { log.error("This engine was forced to close inbound, without having received the " + "proper SSL/TLS close notification message from the peer, due to end of stream."); } - sslEngine.closeOutbound(); handshakeStatus = sslEngine.getHandshakeStatus(); break; - } else if (!receivedBuffer.hasRemaining()) { receivedBuffer.clear(); return SKIP_READ_PACKETS; } - try { log.debug(receivedBuffer, buff -> "Try to unwrap data:\n" + hexDump(buff)); result = sslEngine.unwrap(receivedBuffer, EMPTY_BUFFERS); @@ -127,7 +120,6 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { handshakeStatus = sslEngine.getHandshakeStatus(); break; } - switch (result.getStatus()) { case OK: break; @@ -157,22 +149,17 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { return SKIP_READ_PACKETS; } case NEED_TASK: { - Runnable task; - while ((task = sslEngine.getDelegatedTask()) != null) { log.debug(task, "Execute SSL Engine's task:[%s]"::formatted); task.run(); } - handshakeStatus = sslEngine.getHandshakeStatus(); log.debug(handshakeStatus, "Handshake status:[%s] after engine tasks"::formatted); - if (handshakeStatus == HandshakeStatus.NEED_UNWRAP && !receivedBuffer.hasRemaining()) { sslNetworkBuffer.clear(); return SKIP_READ_PACKETS; } - break; } default: { @@ -182,14 +169,11 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { } if (!receivedBuffer.hasRemaining()) { - // if buffer is empty and status is FINISHED then we can notify writer if (handshakeStatus == HandshakeStatus.FINISHED) { packetWriter.accept(SslWritableNetworkPacket.getInstance()); } - receivedBuffer.clear(); - return SKIP_READ_PACKETS; } @@ -197,9 +181,7 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { } protected int decryptAndRead(ByteBuffer receivedBuffer) { - int total = 0; - while (receivedBuffer.hasRemaining()) { SSLEngineResult result; try { @@ -208,7 +190,6 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { } catch (SSLException e) { throw new IllegalStateException(e); } - switch (result.getStatus()) { case OK: { sslDataBuffer.flip(); @@ -221,7 +202,7 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { return decryptAndRead(receivedBuffer); } case CLOSED: { - closeConnection(); + connection.close(); return SKIP_READ_PACKETS; } default: { @@ -246,12 +227,9 @@ private void increaseDataBuffer() { sslDataBuffer = NetworkUtils.increaseApplicationBuffer(sslDataBuffer, bufferAllocator, sslEngine); } - protected void closeConnection() { - try { - sslEngine.closeOutbound(); - socketChannel.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } + @Override + public void close() { + sslEngine.closeOutbound(); + super.close(); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java index 96aa4fe8..fd7f6c84 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java @@ -1,11 +1,15 @@ package javasabr.rlib.network.packet.impl; import java.nio.ByteBuffer; +import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.experimental.Accessors; /** * @author JavaSaBr */ +@Getter +@Accessors(fluent = true, chain = false) @RequiredArgsConstructor public class StringWritableNetworkPacket extends AbstractWritableNetworkPacket { diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java index 23c6bed6..ebbed521 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java @@ -11,13 +11,15 @@ import java.util.List; import java.util.Scanner; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; import javasabr.rlib.common.util.ObjectUtils; import javasabr.rlib.common.util.StringUtils; +import javasabr.rlib.common.util.ThreadUtils; import javasabr.rlib.common.util.Utils; -import javasabr.rlib.logger.api.Logger; import javasabr.rlib.logger.api.LoggerLevel; import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.client.ClientNetwork; @@ -33,6 +35,7 @@ import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; +import lombok.CustomLog; import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -42,24 +45,23 @@ * * @author JavaSaBr */ +@CustomLog public class StringSslNetworkTest extends BaseNetworkTest { - private static final Logger LOGGER = LoggerManager.getLogger(StringSslNetworkTest.class); - @Test @SneakyThrows void certificatesTest() { InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); - SSLContext clientSSLContext = NetworkUtils.createAllTrustedClientSslContext(); + SSLContext clientSslContext = NetworkUtils.createAllTrustedClientSslContext(); int serverPort = NetworkUtils.getAvailablePort(10000); SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory(); ServerSocket serverSocket = serverSocketFactory.createServerSocket(serverPort); - SSLSocketFactory clientSocketFactory = clientSSLContext.getSocketFactory(); + SSLSocketFactory clientSocketFactory = clientSslContext.getSocketFactory(); SSLSocket clientSocket = (SSLSocket) clientSocketFactory.createSocket("localhost", serverPort); var clientSocketOnServer = serverSocket.accept(); @@ -78,7 +80,8 @@ void certificatesTest() { @Test @SneakyThrows - void serverSSLNetworkTest() { + void serverSslNetworkTest() { + //LoggerManager.enable(StringSslNetworkTest.class, LoggerLevel.INFO); InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); @@ -95,7 +98,7 @@ void serverSSLNetworkTest() { .flatMap(Connection::receivedEvents) .subscribe(event -> { var message = event.packet().data(); - LOGGER.info("Received from client: " + message); + log.info(message, "Received from client:[%s]"::formatted); event.connection().send(new StringWritableNetworkPacket("Echo: " + message)); }); @@ -103,11 +106,11 @@ void serverSSLNetworkTest() { SSLSocketFactory sslSocketFactory = clientSslContext.getSocketFactory(); SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(serverAddress.getHostName(), serverAddress.getPort()); + StringWritableNetworkPacket writableNetworkPacket = new StringWritableNetworkPacket("Hello SSL"); + var buffer = ByteBuffer.allocate(1024); buffer.position(2); - - new StringWritableNetworkPacket("Hello SSL").write(buffer); - + writableNetworkPacket.write(buffer); buffer.putShort(0, (short) buffer.position()); buffer.flip(); @@ -128,18 +131,16 @@ void serverSSLNetworkTest() { StringReadablePacket response = new StringReadablePacket(); response.read(buffer, packetLength - 2); - LOGGER.info("Response: " + response.data()); + log.info(response.data(), "Response:[%s]"::formatted); serverNetwork.shutdown(); } @Test @SneakyThrows - void clientSSLNetworkTest() { - - System.setProperty("javax.net.debug", "all"); - //LoggerManager.enable(AbstractSSLPacketWriter.class, LoggerLevel.DEBUG); - //LoggerManager.enable(AbstractSSLPacketReader.class, LoggerLevel.DEBUG); + void clientSslNetworkTest() { + //System.setProperty("javax.net.debug", "all"); + //LoggerManager.enable(StringSslNetworkTest.class, LoggerLevel.INFO); InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext sslContext = NetworkUtils.createSslContext(keystoreFile, "test"); @@ -162,7 +163,7 @@ void clientSSLNetworkTest() { .doOnError(Throwable::printStackTrace) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { - LOGGER.info("Received from server: " + event.packet().data()); + log.info(event.packet().data(), "Received from server:[%s]"::formatted); counter.countDown(); }); @@ -184,13 +185,13 @@ void clientSSLNetworkTest() { Assertions.assertEquals("Hello SSL", receivedPacket.data()); - LOGGER.info("Received from client: " + receivedPacket.data()); + log.info(receivedPacket.data(), "Received from client:[%s]"::formatted); + + StringWritableNetworkPacket writableNetworkPacket = new StringWritableNetworkPacket("Echo: Hello SSL"); buffer.clear(); buffer.position(2); - - new StringWritableNetworkPacket("Echo: Hello SSL").write(buffer); - + writableNetworkPacket.write(buffer); buffer.putShort(0, (short) buffer.position()); buffer.flip(); @@ -211,14 +212,12 @@ void clientSSLNetworkTest() { @Test @SneakyThrows void echoNetworkTest() { - //System.setProperty("javax.net.debug", "all"); - //LoggerManager.enable(AbstractPacketWriter.class, LoggerLevel.DEBUG); - //LoggerManager.enable(AbstractSSLPacketWriter.class, LoggerLevel.DEBUG); - //LoggerManager.enable(AbstractSSLPacketReader.class, LoggerLevel.DEBUG); + LoggerManager.enable(StringSslNetworkTest.class, LoggerLevel.INFO); InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); + ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); ServerNetwork serverNetwork = NetworkFactory.stringDataSslServerNetwork( ServerNetworkConfig.DEFAULT_SERVER, @@ -235,7 +234,7 @@ void echoNetworkTest() { .flatMap(Connection::receivedEvents) .subscribe(event -> { var message = event.packet().data(); - LOGGER.info("Received from client: " + message); + log.info(message, "Received from client:[%s]"::formatted); event.connection().send(new StringWritableNetworkPacket("Echo: " + message)); }); @@ -249,21 +248,32 @@ void echoNetworkTest() { .connectReactive(serverAddress) .doOnNext(connection -> IntStream .range(10, expectedReceivedPackets + 10) - .forEach(length -> connection.send(newMessage(9, length)))) + .forEach(length -> { + var packet = newMessage(9, length); + int delay = ThreadLocalRandom + .current() + .nextInt(2000); + executor.schedule( + () -> { + connection.send(packet); + log.info(packet.data().length(), "Send [%s] symbols to server"::formatted); + }, delay, TimeUnit.MILLISECONDS); + })) .doOnError(Throwable::printStackTrace) .flatMapMany(Connection::receivedEvents) .subscribe(event -> { - LOGGER.info("Received from server: " + event.packet().data()); + log.info(event.packet().data(), "Received from server:[%s]"::formatted); counter.countDown(); }); Assertions.assertTrue( - counter.await(1000, TimeUnit.MILLISECONDS), + counter.await(60, TimeUnit.SECONDS), "Still wait for " + counter.getCount() + " packets..."); serverNetwork.shutdown(); clientNetwork.shutdown(); + ThreadUtils.sleep(30000); //LoggerManager.disable(AbstractSSLPacketWriter.class, LoggerLevel.DEBUG); //LoggerManager.disable(AbstractSSLPacketReader.class, LoggerLevel.DEBUG); //LoggerManager.disable(AbstractPacketWriter.class, LoggerLevel.DEBUG); @@ -293,7 +303,7 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { var pendingPacketsOnServer = serverToClient .receivedPackets() - .doOnNext(packet -> LOGGER.info("Received from client: " + packet.data())) + .doOnNext(packet -> log.info("Received from client: " + packet.data())) .buffer(packetCount); var messages = IntStream diff --git a/rlib-plugin-system/build.gradle b/rlib-plugin-system/build.gradle index cdc11bce..f233f472 100644 --- a/rlib-plugin-system/build.gradle +++ b/rlib-plugin-system/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon diff --git a/rlib-reference/build.gradle b/rlib-reference/build.gradle index 3ba0c727..0a074db2 100644 --- a/rlib-reference/build.gradle +++ b/rlib-reference/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { compileOnly projects.rlibReusable diff --git a/rlib-reusable/build.gradle b/rlib-reusable/build.gradle index d065f972..a8b1acac 100644 --- a/rlib-reusable/build.gradle +++ b/rlib-reusable/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCollections diff --git a/rlib-testcontainers/build.gradle b/rlib-testcontainers/build.gradle index 16131cd8..18df8e69 100644 --- a/rlib-testcontainers/build.gradle +++ b/rlib-testcontainers/build.gradle @@ -1,4 +1,7 @@ -apply from: "$rootDir/gradle/configure-publishing.gradle" +plugins { + id("configure-java") + id("configure-publishing") +} dependencies { api projects.rlibCommon diff --git a/test-coverage/build.gradle b/test-coverage/build.gradle index af53c2c4..91ce11b2 100644 --- a/test-coverage/build.gradle +++ b/test-coverage/build.gradle @@ -1,4 +1,6 @@ -apply plugin: "jacoco-report-aggregation" +plugins { + id("jacoco-report-aggregation") +} dependencies { jacocoAggregation projects.rlibClasspath From a6153807dbe762357cd681e2c7e0e19a4fe514ba Mon Sep 17 00:00:00 2001 From: javasabr Date: Sat, 4 Oct 2025 11:54:37 +0200 Subject: [PATCH 08/15] started working on network load test --- .../rlib/network/StringNetworkLoadTest.java | 24 ++++++++++++++++++- .../javasabr/rlib/network/package-info.java | 4 ++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 rlib-network/src/loadTest/java/javasabr/rlib/network/package-info.java diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java index 04e11f00..da60e1bb 100644 --- a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java @@ -23,8 +23,30 @@ @CustomLog public class StringNetworkLoadTest { - private static class TestClient { + private static class TestClient implements AutoCloseable { + private static final AtomicInteger ID_FACTORY = new AtomicInteger(); + + String clientId = "Client_%s".formatted(ID_FACTORY.incrementAndGet()); + NetworkConfig networkConfig = NetworkConfig.SimpleNetworkConfig.builder() + .groupName(clientId) + .writeBufferSize(256) + .readBufferSize(256) + .pendingBufferSize(512) + .build(); + + BufferAllocator clientAllocator = new DefaultBufferAllocator(networkConfig); + ClientNetwork network = NetworkFactory + .stringDataClientNetwork(networkConfig, clientAllocator); + + void connectAndSendMessages(InetSocketAddress serverAddress, int messages, CountDownLatch ) { + + } + + @Override + public void close() throws Exception { + network.shutdown(); + } } @Test diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/package-info.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/package-info.java new file mode 100644 index 00000000..53222c6a --- /dev/null +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.rlib.network; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file From bc39f19f210264714ac6845afd28bd7c7fca1242 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sat, 4 Oct 2025 21:29:37 +0200 Subject: [PATCH 09/15] add load tests for string network --- .../src/main/groovy/configure-java.gradle | 2 + .../rlib/network/StringNetworkLoadTest.java | 139 ++++++++++++------ .../impl/AbstractNetworkPacketWriter.java | 7 +- .../impl/StringWritableNetworkPacket.java | 2 +- 4 files changed, 105 insertions(+), 45 deletions(-) diff --git a/buildSrc/src/main/groovy/configure-java.gradle b/buildSrc/src/main/groovy/configure-java.gradle index d076ad57..f59e6e5e 100644 --- a/buildSrc/src/main/groovy/configure-java.gradle +++ b/buildSrc/src/main/groovy/configure-java.gradle @@ -43,6 +43,8 @@ tasks.register("loadTest", Test) { failOnNoDiscoveredTests = false testClassesDirs = sourceSets.loadTest.output.classesDirs classpath = sourceSets.loadTest.runtimeClasspath + minHeapSize = "128m" + maxHeapSize = "4G" } dependencies { diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java index da60e1bb..2a34d5d3 100644 --- a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java @@ -1,13 +1,20 @@ package javasabr.rlib.network; -import static javasabr.rlib.network.ServerNetworkConfig.DEFAULT_SERVER; - import java.net.InetSocketAddress; +import java.util.ArrayList; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.IntStream; +import java.util.concurrent.atomic.LongAccumulator; import javasabr.rlib.common.util.StringUtils; +import javasabr.rlib.common.util.ThreadUtils; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.api.LoggerManager; import javasabr.rlib.network.ServerNetworkConfig.SimpleServerNetworkConfig; import javasabr.rlib.network.client.ClientNetwork; import javasabr.rlib.network.impl.DefaultBufferAllocator; @@ -18,11 +25,13 @@ import lombok.SneakyThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; @CustomLog public class StringNetworkLoadTest { + public static final int MAX_ITERATIONS = 10; + public static final int MAX_SEND_DELAY = 60_000; + private static class TestClient implements AutoCloseable { private static final AtomicInteger ID_FACTORY = new AtomicInteger(); @@ -36,15 +45,51 @@ private static class TestClient implements AutoCloseable { .build(); BufferAllocator clientAllocator = new DefaultBufferAllocator(networkConfig); + ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); ClientNetwork network = NetworkFactory .stringDataClientNetwork(networkConfig, clientAllocator); - void connectAndSendMessages(InetSocketAddress serverAddress, int messages, CountDownLatch ) { + void connectAndSendMessages( + InetSocketAddress serverAddress, + int messages) { + Thread thread = new Thread(() -> { + + ThreadLocalRandom random = ThreadLocalRandom.current(); + + ThreadUtils.sleep(random.nextInt(5000)); + StringDataConnection connection = network.connect(serverAddress); + + var tasks = new ArrayList>(messages); + for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) { + for (int m = 0; m < messages; m++) { + int delay = random.nextInt(MAX_SEND_DELAY); + ScheduledFuture schedule = executor.schedule( + () -> { + StringWritableNetworkPacket message = newMessage(10, 10240); + connection.send(message); + }, delay, TimeUnit.MILLISECONDS); + tasks.add(schedule); + } + + for (ScheduledFuture task : tasks) { + try { + task.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + tasks.clear(); + } + }); + thread.setName(clientId); + thread.setUncaughtExceptionHandler((t, e) -> log.error(e)); + thread.start(); } @Override - public void close() throws Exception { + public void close() { network.shutdown(); } } @@ -52,25 +97,25 @@ public void close() throws Exception { @Test @SneakyThrows void testServerWithMultiplyClients() { - //LoggerManager.enable(AbstractPacketWriter.class, LoggerLevel.DEBUG); + LoggerManager.enable(StringNetworkLoadTest.class, LoggerLevel.INFO); var serverConfig = SimpleServerNetworkConfig .builder() .threadGroupSize(10) + .writeBufferSize(1024) + .readBufferSize(1024) + .pendingBufferSize(2048) .build(); var serverAllocator = new DefaultBufferAllocator(serverConfig); - var clientAllocator = new DefaultBufferAllocator(NetworkConfig.DEFAULT_CLIENT); + ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); int clientCount = 100; - int packetsPerClient = 100; - int minMessageLength = 10; - int maxMessageLength = (int) (DEFAULT_SERVER.readBufferSize() * 1.5); + int messagesPerIteration = 1_000; + int expectedMessages = clientCount * messagesPerIteration * MAX_ITERATIONS; - var counter = new CountDownLatch(clientCount * packetsPerClient); - var sentPacketsToServer = new AtomicInteger(); - var receivedPacketsOnServer = new AtomicInteger(); - var receivedPacketsOnClients = new AtomicInteger(); + var finalWaiter = new CountDownLatch(1); + var receivedClientPackersPerSecond = new LongAccumulator(Long::sum, 0); ServerNetwork serverNetwork = NetworkFactory.stringDataServerNetwork(serverConfig, serverAllocator); InetSocketAddress serverAddress = serverNetwork.start(); @@ -78,41 +123,49 @@ void testServerWithMultiplyClients() { serverNetwork .accepted() .flatMap(Connection::receivedEvents) - .doOnNext(event -> receivedPacketsOnServer.incrementAndGet()) - .subscribe(event -> event.connection().send(newMessage(minMessageLength, maxMessageLength))); - - Flux - .fromStream(IntStream - .range(0, clientCount) - .mapToObj(value -> NetworkFactory.stringDataClientNetwork(NetworkConfig.DEFAULT_CLIENT, clientAllocator))) - .doOnDiscard(ClientNetwork.class, Network::shutdown) - .flatMap(client -> client.connectReactive(serverAddress)) - .flatMap(connection -> { - - var receivedEvents = connection.receivedEvents(); - - for (int i = 0; i < packetsPerClient; i++) { - connection.send(newMessage(minMessageLength, maxMessageLength)); - sentPacketsToServer.incrementAndGet(); - } - - return receivedEvents; + .doOnNext(receivedPacketEvent -> { + //log.info(receivedPacketEvent, "Server received:[%s]"::formatted); + receivedClientPackersPerSecond.accumulate(1); + //counter.countDown(); }) - .subscribe(event -> { - receivedPacketsOnClients.incrementAndGet(); - counter.countDown(); - }); + .subscribe(); + + initReceivedMessagesTracker( + scheduledExecutor, + receivedClientPackersPerSecond, + finalWaiter); + + var clients = new ArrayList(); + + for(int c = 0; c < clientCount; c++) { + TestClient testClient = new TestClient(); + testClient.connectAndSendMessages(serverAddress, messagesPerIteration); + } Assertions - .assertTrue( - counter.await(10000, TimeUnit.MILLISECONDS), - "Still wait for " + counter.getCount() + " packets... " + "Sent packets to server: " + sentPacketsToServer - + ", " + "Received packets on server: " + receivedPacketsOnServer + ", " + "Received packets on clients: " - + receivedPacketsOnClients); + .assertTrue(finalWaiter.await(120_000, TimeUnit.MILLISECONDS), + "Still not received [%s] -> [%s] messages".formatted(expectedMessages, finalWaiter.getCount())); + + for (TestClient client : clients) { + client.close(); + } serverNetwork.shutdown(); } + private static void initReceivedMessagesTracker( + ScheduledExecutorService scheduledExecutor, + LongAccumulator receivedClientPackersPerSecond, + CountDownLatch finalWaiter) { + scheduledExecutor.scheduleAtFixedRate(() -> { + long received = receivedClientPackersPerSecond.getThenReset(); + log.info(received, "Server receiving [%s] messages/sec"::formatted); + if (received == 0) { + finalWaiter.countDown(); + } + }, 1, 1, TimeUnit.SECONDS); + } + private static StringWritableNetworkPacket newMessage(int minMessageLength, int maxMessageLength) { return new StringWritableNetworkPacket(StringUtils.generate(minMessageLength, maxMessageLength)); } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java index 0e3f93ee..d0198e2f 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java @@ -3,6 +3,7 @@ import static javasabr.rlib.network.util.NetworkUtils.EMPTY_BUFFER; import static javasabr.rlib.network.util.NetworkUtils.hexDump; +import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; @@ -344,7 +345,11 @@ protected void handleSuccessfulWritingData(Integer wroteBytes, WritableNetworkPa * @param packet the packet. */ protected void handleFailedWritingData(Throwable exception, WritableNetworkPacket packet) { - log.error(new RuntimeException("Failed writing packet: " + packet, exception)); + log.error(new RuntimeException("Failed writing packet:" + packet, exception)); + if (exception instanceof IOException) { + connection.close(); + return; + } if (!connection.closed()) { if (writing.compareAndSet(true, false)) { tryToSendNextPacket(); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java index fd7f6c84..e8c63323 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java @@ -28,6 +28,6 @@ public int expectedLength() { @Override public String toString() { - return "StringWritablePacket {\n" + "\"\tdataLength\":" + data.length() + "\n}"; + return "StringWritablePacket[length:" + data.length() + "]"; } } From 412db3a83f8bf95417ddb186956ff8a2be784171 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 5 Oct 2025 17:15:23 +0200 Subject: [PATCH 10/15] fixing ssl implementation --- .../rlib/common/util/BufferUtils.java | 31 +-- .../rlib/network/StringNetworkLoadTest.java | 70 ++++-- .../network/StringSslNetworkLoadTest.java | 219 ++++++++++++++++++ .../loadTest/resources/ssl/rlib_test_cert.p12 | Bin 0 -> 2581 bytes .../loadTest/resources/ssl/rlib_test_cert.pem | 23 ++ .../loadTest/resources/ssl/rlib_test_key.pem | 28 +++ .../packet/impl/AbstractNetworkPacket.java | 6 +- .../impl/AbstractNetworkPacketReader.java | 6 +- .../impl/AbstractReadableNetworkPacket.java | 4 +- .../impl/AbstractSslNetworkPacketReader.java | 111 ++++++--- .../packet/impl/StringReadablePacket.java | 4 + .../impl/StringWritableNetworkPacket.java | 6 +- .../rlib/network/util/NetworkUtils.java | 30 ++- .../javasabr/rlib/network/util/SslUtils.java | 16 ++ 14 files changed, 465 insertions(+), 89 deletions(-) create mode 100644 rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java create mode 100644 rlib-network/src/loadTest/resources/ssl/rlib_test_cert.p12 create mode 100644 rlib-network/src/loadTest/resources/ssl/rlib_test_cert.pem create mode 100644 rlib-network/src/loadTest/resources/ssl/rlib_test_key.pem create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/util/SslUtils.java diff --git a/rlib-common/src/main/java/javasabr/rlib/common/util/BufferUtils.java b/rlib-common/src/main/java/javasabr/rlib/common/util/BufferUtils.java index 4b278589..25ae6b5e 100644 --- a/rlib-common/src/main/java/javasabr/rlib/common/util/BufferUtils.java +++ b/rlib-common/src/main/java/javasabr/rlib/common/util/BufferUtils.java @@ -13,8 +13,6 @@ import org.jspecify.annotations.NullMarked; /** - * The utility class. - * * @author JavaSaBr */ @NullMarked @@ -34,26 +32,19 @@ public class BufferUtils { * @param source the source buffer * @return the target buffer. */ - public ByteBuffer loadFrom(ByteBuffer source, ByteBuffer target) { - + public static ByteBuffer loadFrom(ByteBuffer source, ByteBuffer target) { var prevLimit = source.limit(); try { - target.clear(); - - var skip = source.remaining() - target.remaining(); - + int skip = source.remaining() - target.remaining(); if (skip > 0) { source.limit(prevLimit - skip); } - target.put(source); target.flip(); - } finally { source.limit(prevLimit); } - return target; } @@ -63,7 +54,7 @@ public ByteBuffer loadFrom(ByteBuffer source, ByteBuffer target) { * @param size the byte buffer's size. * @return the new mapped byte buffer. */ - public MappedByteBuffer allocateRWMappedByteBuffer(int size) { + public static MappedByteBuffer allocateRWMappedByteBuffer(int size) { try { var tempFile = Files.createTempFile("rlib_common_util_", "_buffer_utils.bin"); @@ -77,21 +68,31 @@ public MappedByteBuffer allocateRWMappedByteBuffer(int size) { } } - public ByteBuffer putToAndFlip(ByteBuffer buffer, ByteBuffer additional) { + public static ByteBuffer putToAndFlip(ByteBuffer buffer, ByteBuffer additional) { return buffer .limit(buffer.capacity()) .put(additional) .flip(); } + public static ByteBuffer appendAndClear(ByteBuffer buffer, ByteBuffer additional) { + ByteBuffer result = buffer + .position(buffer.limit()) + .limit(buffer.capacity()) + .put(additional) + .flip(); + additional.clear(); + return result; + } + /** - * Create a new byte buffer with with writing some data inside the consumer and to flip in the result. + * Create a new byte buffer with writing some data inside the consumer and to flip in the result. * * @param size the buffer's size. * @param consumer the consumer to write data. * @return the flipped buffer. */ - public ByteBuffer prepareBuffer(int size, Consumer consumer) { + public static ByteBuffer prepareBuffer(int size, Consumer consumer) { var buffer = ByteBuffer.allocate(size); consumer.accept(buffer); return buffer.flip(); diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java index 2a34d5d3..5b9922f9 100644 --- a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringNetworkLoadTest.java @@ -22,7 +22,9 @@ import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; import javasabr.rlib.network.server.ServerNetwork; import lombok.CustomLog; +import lombok.Getter; import lombok.SneakyThrows; +import lombok.experimental.Accessors; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -30,7 +32,7 @@ public class StringNetworkLoadTest { public static final int MAX_ITERATIONS = 10; - public static final int MAX_SEND_DELAY = 60_000; + public static final int MAX_SEND_DELAY = 20_000; private static class TestClient implements AutoCloseable { @@ -48,6 +50,11 @@ private static class TestClient implements AutoCloseable { ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); ClientNetwork network = NetworkFactory .stringDataClientNetwork(networkConfig, clientAllocator); + StatisticsCollector statistics; + + private TestClient(StatisticsCollector statistics) { + this.statistics = statistics; + } void connectAndSendMessages( InetSocketAddress serverAddress, @@ -59,6 +66,10 @@ void connectAndSendMessages( ThreadUtils.sleep(random.nextInt(5000)); StringDataConnection connection = network.connect(serverAddress); + connection.onReceive((serverConnection, packet) -> statistics + .receivedServerPackersPerSecond() + .accumulate(1)); + var tasks = new ArrayList>(messages); for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) { @@ -94,6 +105,14 @@ public void close() { } } + @Getter + @Accessors(fluent = true) + private static class StatisticsCollector { + LongAccumulator receivedClientPackersPerSecond = new LongAccumulator(Long::sum, 0); + LongAccumulator sentEchoPackersPerSecond = new LongAccumulator(Long::sum, 0); + LongAccumulator receivedServerPackersPerSecond = new LongAccumulator(Long::sum, 0); + } + @Test @SneakyThrows void testServerWithMultiplyClients() { @@ -110,40 +129,41 @@ void testServerWithMultiplyClients() { var serverAllocator = new DefaultBufferAllocator(serverConfig); ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); - int clientCount = 100; - int messagesPerIteration = 1_000; + int clientCount = 200; + int messagesPerIteration = 3_000; int expectedMessages = clientCount * messagesPerIteration * MAX_ITERATIONS; var finalWaiter = new CountDownLatch(1); - var receivedClientPackersPerSecond = new LongAccumulator(Long::sum, 0); + var statistics = new StatisticsCollector(); ServerNetwork serverNetwork = NetworkFactory.stringDataServerNetwork(serverConfig, serverAllocator); InetSocketAddress serverAddress = serverNetwork.start(); - serverNetwork - .accepted() - .flatMap(Connection::receivedEvents) - .doOnNext(receivedPacketEvent -> { - //log.info(receivedPacketEvent, "Server received:[%s]"::formatted); - receivedClientPackersPerSecond.accumulate(1); - //counter.countDown(); - }) - .subscribe(); + serverNetwork.onAccept(accepted -> accepted + .onReceive((connection, packet) -> { + statistics + .receivedClientPackersPerSecond() + .accumulate(1); + connection.send(new StringWritableNetworkPacket("Echo: " + packet.data())); + statistics + .sentEchoPackersPerSecond() + .accumulate(1); + })); initReceivedMessagesTracker( scheduledExecutor, - receivedClientPackersPerSecond, + statistics, finalWaiter); var clients = new ArrayList(); for(int c = 0; c < clientCount; c++) { - TestClient testClient = new TestClient(); + TestClient testClient = new TestClient(statistics); testClient.connectAndSendMessages(serverAddress, messagesPerIteration); } Assertions - .assertTrue(finalWaiter.await(120_000, TimeUnit.MILLISECONDS), + .assertTrue(finalWaiter.await(300_000, TimeUnit.MILLISECONDS), "Still not received [%s] -> [%s] messages".formatted(expectedMessages, finalWaiter.getCount())); for (TestClient client : clients) { @@ -155,15 +175,29 @@ void testServerWithMultiplyClients() { private static void initReceivedMessagesTracker( ScheduledExecutorService scheduledExecutor, - LongAccumulator receivedClientPackersPerSecond, + StatisticsCollector statistics, CountDownLatch finalWaiter) { scheduledExecutor.scheduleAtFixedRate(() -> { - long received = receivedClientPackersPerSecond.getThenReset(); + long received = statistics + .receivedClientPackersPerSecond() + .getThenReset(); log.info(received, "Server receiving [%s] messages/sec"::formatted); if (received == 0) { finalWaiter.countDown(); } }, 1, 1, TimeUnit.SECONDS); + scheduledExecutor.scheduleAtFixedRate(() -> { + long received = statistics + .sentEchoPackersPerSecond() + .getThenReset(); + log.info(received, "Sent echo packets [%s] messages/sec"::formatted); + }, 1, 1, TimeUnit.SECONDS); + scheduledExecutor.scheduleAtFixedRate(() -> { + long received = statistics + .receivedServerPackersPerSecond() + .getThenReset(); + log.info(received, "Clients receiving [%s] echo messages/sec"::formatted); + }, 1, 1, TimeUnit.SECONDS); } private static StringWritableNetworkPacket newMessage(int minMessageLength, int maxMessageLength) { diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java new file mode 100644 index 00000000..55c0f834 --- /dev/null +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java @@ -0,0 +1,219 @@ +package javasabr.rlib.network; + +import java.io.InputStream; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAccumulator; +import javasabr.rlib.common.util.StringUtils; +import javasabr.rlib.common.util.ThreadUtils; +import javasabr.rlib.logger.api.LoggerLevel; +import javasabr.rlib.logger.api.LoggerManager; +import javasabr.rlib.network.ServerNetworkConfig.SimpleServerNetworkConfig; +import javasabr.rlib.network.client.ClientNetwork; +import javasabr.rlib.network.impl.DefaultBufferAllocator; +import javasabr.rlib.network.impl.StringDataConnection; +import javasabr.rlib.network.impl.StringDataSslConnection; +import javasabr.rlib.network.packet.impl.AbstractSslNetworkPacketReader; +import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; +import javasabr.rlib.network.server.ServerNetwork; +import javasabr.rlib.network.util.NetworkUtils; +import javax.net.ssl.SSLContext; +import lombok.CustomLog; +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.experimental.Accessors; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@CustomLog +public class StringSslNetworkLoadTest { + + public static final int MAX_ITERATIONS = 10; + public static final int MAX_SEND_DELAY = 20_000; + + private static class TestClient implements AutoCloseable { + + private static final AtomicInteger ID_FACTORY = new AtomicInteger(); + + String clientId = "Client_%s".formatted(ID_FACTORY.incrementAndGet()); + NetworkConfig networkConfig = NetworkConfig.SimpleNetworkConfig.builder() + .groupName(clientId) + .writeBufferSize(256) + .readBufferSize(256) + .pendingBufferSize(512) + .build(); + + BufferAllocator clientAllocator = new DefaultBufferAllocator(networkConfig); + ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + ClientNetwork network = NetworkFactory + .stringDataSslClientNetwork(networkConfig, clientAllocator, NetworkUtils.createAllTrustedClientSslContext()); + StatisticsCollector statistics; + + private TestClient(StatisticsCollector statistics) { + this.statistics = statistics; + } + + void connectAndSendMessages( + InetSocketAddress serverAddress, + int messages) { + Thread thread = new Thread(() -> { + + ThreadLocalRandom random = ThreadLocalRandom.current(); + + ThreadUtils.sleep(random.nextInt(5000)); + StringDataSslConnection connection = network.connect(serverAddress); + + connection.onReceive((serverConnection, packet) -> statistics + .receivedServerPackersPerSecond() + .accumulate(1)); + + var tasks = new ArrayList>(messages); + + for (int iteration = 0; iteration < MAX_ITERATIONS; iteration++) { + for (int m = 0; m < messages; m++) { + int delay = random.nextInt(MAX_SEND_DELAY); + ScheduledFuture schedule = executor.schedule( + () -> { + StringWritableNetworkPacket message = newMessage(10, 10240); // 10240 + connection.send(message); + }, delay, TimeUnit.MILLISECONDS); + tasks.add(schedule); + } + + for (ScheduledFuture task : tasks) { + try { + task.get(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + } + + tasks.clear(); + } + }); + thread.setName(clientId); + thread.setUncaughtExceptionHandler((t, e) -> log.error(e)); + thread.start(); + } + + @Override + public void close() { + network.shutdown(); + } + } + + @Getter + @Accessors(fluent = true) + private static class StatisticsCollector { + LongAccumulator receivedClientPackersPerSecond = new LongAccumulator(Long::sum, 0); + LongAccumulator sentEchoPackersPerSecond = new LongAccumulator(Long::sum, 0); + LongAccumulator receivedServerPackersPerSecond = new LongAccumulator(Long::sum, 0); + } + + @Test + @SneakyThrows + void testServerWithMultiplyClients() { + LoggerManager.enable(StringSslNetworkLoadTest.class, LoggerLevel.INFO); + LoggerManager.enable(AbstractSslNetworkPacketReader.class, LoggerLevel.DEBUG); + + var serverConfig = SimpleServerNetworkConfig + .builder() + .threadGroupSize(10) + .writeBufferSize(1024) + .readBufferSize(1024) + .pendingBufferSize(2048) + .build(); + + var serverAllocator = new DefaultBufferAllocator(serverConfig); + ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); + + int clientCount = 1; + int messagesPerIteration = 300; + int expectedMessages = clientCount * messagesPerIteration * MAX_ITERATIONS; + + var finalWaiter = new CountDownLatch(2); + var statistics = new StatisticsCollector(); + + InputStream keystoreFile = StringSslNetworkLoadTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); + SSLContext serverSslContext = NetworkUtils.createSslContext(keystoreFile, "test"); + + ServerNetwork serverNetwork = NetworkFactory + .stringDataSslServerNetwork(serverConfig, serverAllocator, serverSslContext); + InetSocketAddress serverAddress = serverNetwork.start(); + + serverNetwork.onAccept(accepted -> accepted + .onReceive((connection, packet) -> { + statistics + .receivedClientPackersPerSecond() + .accumulate(1); + //connection.send(new StringWritableNetworkPacket("Echo: " + packet.data())); + statistics + .sentEchoPackersPerSecond() + .accumulate(1); + })); + + initReceivedMessagesTracker( + scheduledExecutor, + statistics, + finalWaiter); + + var clients = new ArrayList(); + + for(int c = 0; c < clientCount; c++) { + TestClient testClient = new TestClient(statistics); + testClient.connectAndSendMessages(serverAddress, messagesPerIteration); + } + + ThreadUtils.sleep(30000); + finalWaiter.countDown(); + + Assertions + .assertTrue(finalWaiter.await(300_000, TimeUnit.MILLISECONDS), + "Still not received [%s] -> [%s] messages".formatted(expectedMessages, finalWaiter.getCount())); + + for (TestClient client : clients) { + client.close(); + } + + serverNetwork.shutdown(); + } + + private static void initReceivedMessagesTracker( + ScheduledExecutorService scheduledExecutor, + StatisticsCollector statistics, + CountDownLatch finalWaiter) { + scheduledExecutor.scheduleAtFixedRate(() -> { + long received = statistics + .receivedClientPackersPerSecond() + .getThenReset(); + log.info(received, "Server receiving [%s] messages/sec"::formatted); + if (received == 0) { + // finalWaiter.countDown(); + } + }, 1, 1, TimeUnit.SECONDS); + scheduledExecutor.scheduleAtFixedRate(() -> { + long received = statistics + .sentEchoPackersPerSecond() + .getThenReset(); + log.info(received, "Sent echo packets [%s] messages/sec"::formatted); + }, 1, 1, TimeUnit.SECONDS); + scheduledExecutor.scheduleAtFixedRate(() -> { + long received = statistics + .receivedServerPackersPerSecond() + .getThenReset(); + log.info(received, "Clients receiving [%s] echo messages/sec"::formatted); + }, 1, 1, TimeUnit.SECONDS); + } + + private static StringWritableNetworkPacket newMessage(int minMessageLength, int maxMessageLength) { + return new StringWritableNetworkPacket(StringUtils.generate(minMessageLength, maxMessageLength)); + } +} diff --git a/rlib-network/src/loadTest/resources/ssl/rlib_test_cert.p12 b/rlib-network/src/loadTest/resources/ssl/rlib_test_cert.p12 new file mode 100644 index 0000000000000000000000000000000000000000..f8ee701821f0813ee0a20c811fc20638c3e6e7c5 GIT binary patch literal 2581 zcmY+^c{CJ?9tUtU#xmAx9m^1+D=tQM*_R3tsmWZ%)?`Se+>9`2xW*nDGnUHO%95QB zvWHM5vy7&U^2^_s8%2&iQ`N`TqHV;rK*=08SVVJj)GMOSq7*CkWsH zka6Ha5DrW^j=Nwu5ayqXn~VebA4e!4faCZf|7id)C^z4~7X$#@Fd-0cLX(nY?U3~l z5Xj3Bivz(}RTvwf1x$OGXc&)lDHv2O)Y_lU37l>>Dehi2zWpN)MvDz;=$4uCPzw4QXAM3;bV96kwKmJ@x(vy4exFwqf2d%o1;Hu zys-2(cN%cS7m*3(JGnNh-Y#x zNo3wtkx$fjj{r*tNagC#A>(9n_i9?-3XY!w>A2QjnuL~#H+ zQTh7vs_06I3FBK!wye6l$Al?lC7nLm+rd8q&1~Pm@Jv-0bv%>1Wo9H`WvFVGsu)HX zeKik``fWYi9LmN1@@Z_t)0%lUuK{S$Hor-4tpmBGO!m{KG^okae0Rnt+czH?J2_lw zg1Z&wg{$O!^5jxxK`y>2tpuQs(m*8ZU5T`4kLF2!8-GimtP_3)3U3?%XM4k2g*7Vd zw$Aj0`boeMM?up#{CT3NZ@VyjDsEVmndMrZG*y3P$Hzh~i|DNSXEKAPmopgP6}8E<_li+wcg7LIj;|j>WMWaqnNW6|cw)Pm!^860 zON8C7oVVGYQy|H@RH5WyqIXdET!h9tp-cimS9u*sWnlbBK#Esboto__x1q?%;tWE@ zMo(`0N42SEfZ3NU!eOX3W(ob(NQLB>d#+ZmJlD3+xnw^Qn@0r(M4wDS7%tTAvS2dR z;0Czgg55Ggz2Mr)bz;H8f~Hy$ z=x9^WMQ5GO&A};;>W=#?By=#dOkE_)Ys4DsFyosN2g8J0b_`tq)v{UUc!+yDeT2&|5jz@09;1<=sh@ zk-lv&Y}BZ|lV=afd7*SJ_KhxmXIETx%c-fR`ZpvFhU2pQA7IEht}`GUm*#P-c6_I} z`TxTW9{_ml(uZS^{`x$PP0lJ2JK1-FB$*u3{yT27F zcp}1(q-$AcnpN%A+Ln0<-e#_Q+I=4eRh;$+p&3(lU&`+Y1HL*dWDx_lXOG@C^Avc! zIs~q_u_zc9vk@t|_qJBXMRC#boQHw%>}8fWaGwFG>L8uo+ac*RL^&BD(v5^*VuCsh zVL1$KeGV#}+doUe$_{us@azAQwyE6}P!gKL6MY!N{;@Qi`T-}kxXy>P{h@~9yLU6s zF*>BN*PEzgzTyS_A%+dNi1T3RoFye481&Ij%!Y2rEBHSQ*ozGN47PxxVl^-aiZ$3UECKiiez^4!)ScjHKX(fB1`EhzDf~zCru=<>1lj}yf+oS*RxXE}=x;c>cPHvIof(I@UYPqm zZ{JY3U7KpoZD3t>j+w2VTb7C*fG18G5No59C-lGutbOUh@^T}9f&7h!c^dFDQpVnNvZFc$n3cGl8XH6DdIZKuu3^q zIdr{i!D8*BXrlIAsUzE{W(jJF%ifRmgUY5azx@H7T7w2ro$PG!%5IQ?vg`$jP#W}CEZSDpTJ{T1=a~nuX50z z#(Z!rd01NocJjYEf+e&iLE`=bqELfw*TZIng_>t*)hW{!k||6ZrU(ObbEyk)0%f>3 nK;nscFA_gti{Sui0m8`@?4_E1Ni2vLgL`d$%>jV^TgiU`?|I^` literal 0 HcmV?d00001 diff --git a/rlib-network/src/loadTest/resources/ssl/rlib_test_cert.pem b/rlib-network/src/loadTest/resources/ssl/rlib_test_cert.pem new file mode 100644 index 00000000..99a41172 --- /dev/null +++ b/rlib-network/src/loadTest/resources/ssl/rlib_test_cert.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDzTCCArWgAwIBAgIUFrbfPa58nThm6Q8PT5mkU2yLffAwDQYJKoZIhvcNAQEL +BQAwdjELMAkGA1UEBhMCVEUxDTALBgNVBAgMBFRlc3QxDTALBgNVBAcMBFRlc3Qx +DTALBgNVBAoMBFRlc3QxDTALBgNVBAsMBFRlc3QxDTALBgNVBAMMBFRlc3QxHDAa +BgkqhkiG9w0BCQEWDXRlc3RAdGVzdC5jb20wHhcNMTkxMjA2MDYwMTA5WhcNMjAx +MjA1MDYwMTA5WjB2MQswCQYDVQQGEwJURTENMAsGA1UECAwEVGVzdDENMAsGA1UE +BwwEVGVzdDENMAsGA1UECgwEVGVzdDENMAsGA1UECwwEVGVzdDENMAsGA1UEAwwE +VGVzdDEcMBoGCSqGSIb3DQEJARYNdGVzdEB0ZXN0LmNvbTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBANqnqAnBBYWf5HBTKOqiwWj1/bbVVYooww3BqRd9 +AyJCmJUpJdYTAh+Yswo//mELaSH9vySKYkoJ/HqdVYr40/TqeRhdGc4UYTokOn8u +mGRsW9hdSsJOOo3UTAFUAs4YteYjEqqUKRefQIb1LETHixYyrAu6g5IwM7nfwY9l +9jm6qiTCZTM5V0oU35Yjg/1bYDWd6emM8CV1dbGCDV/QidYqW9KE8MUqCMdDSFe/ +hOt0I09hHZiH1ZVbNebGaSQivR6vcB2UswuqqkberkvjO28QOk6FJEZ8fxn5RtuP +b+C47j1pHOBZxrHaltQEvk8IhStPqgGaGmzULReOEbQA3TECAwEAAaNTMFEwHQYD +VR0OBBYEFNYonPaRTLJGti0H7UiK7MU2/DsUMB8GA1UdIwQYMBaAFNYonPaRTLJG +ti0H7UiK7MU2/DsUMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +AI+zGveb05Mj8y1bJuqyqIxg91Chgqw4nzvMVfpT03rLmV+0qctg2gwAOhQ3qrOI +RoR7T7cwH4ybQXlk9k3hLot0DfpNv5YPtBkmrGI4eRqmqJunAc/18Evop0nxE9tE +MX/oIa7pJJfzPBZbq1elM9mwD+l+Qf/fQ5qEAFgSOMAw6ZwjFf2xKDrt58RVPcHi +CnzG05YZGpBEtIxz9jJlb4dbShZ1Dz86zJW/k5GLr64x+EDM3Vdu0MlUKNsf/+RA +9bE4I+hMP8GwJGSF/TRKaiDl0Q1rdlyovOAUPfZ4uzBa7yAU+++3Atq6ORYwOdGZ +HaYft/lT2/vMy/HuahcbvgM= +-----END CERTIFICATE----- diff --git a/rlib-network/src/loadTest/resources/ssl/rlib_test_key.pem b/rlib-network/src/loadTest/resources/ssl/rlib_test_key.pem new file mode 100644 index 00000000..0dd66b96 --- /dev/null +++ b/rlib-network/src/loadTest/resources/ssl/rlib_test_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDap6gJwQWFn+Rw +UyjqosFo9f221VWKKMMNwakXfQMiQpiVKSXWEwIfmLMKP/5hC2kh/b8kimJKCfx6 +nVWK+NP06nkYXRnOFGE6JDp/LphkbFvYXUrCTjqN1EwBVALOGLXmIxKqlCkXn0CG +9SxEx4sWMqwLuoOSMDO538GPZfY5uqokwmUzOVdKFN+WI4P9W2A1nenpjPAldXWx +gg1f0InWKlvShPDFKgjHQ0hXv4TrdCNPYR2Yh9WVWzXmxmkkIr0er3AdlLMLqqpG +3q5L4ztvEDpOhSRGfH8Z+Ubbj2/guO49aRzgWcax2pbUBL5PCIUrT6oBmhps1C0X +jhG0AN0xAgMBAAECggEAGc9gjoYyWKufE4M9eTTtD6653DMifcSCAcWyaAthq1Gh +ITpSNQrZXVFxEOys4leueUyym2WaZJL5MqAP0O++VVK4KKAUw7a0I2DTZt/hLTl9 +PfUFNhp13vgIYL/B9QIFtry9H1WN5DPwMf4O06+aQ2yH0nqZvU/jSzWWa47lmbqv +JeH/T5FIOhc/pjqhep+6LFccL6TMGtTUlhID7wzwJFgO+kXKYpeZ5CL2NczAX7jR +Qd75u5igxLub0vR8Y7GG8+1Cvgt1PbHAOi9uOeQJfkT3+hSGCaW6qwXdPJ3N1hCO +4ayqGP8f6vcedDIDbclaWsRhD0kYb2AMci3NTwygAQKBgQD1lQfMjaiR3NqZnLu3 +M8KrGoeNu8GeFYPqXt0WqRVLkVo9nf68kGRjPRo5i/BCVZTUdCq9K4koiM2EMlQB +6creo4UfGR6jBf55Jm2AjzUap/y0wNUJR5JdtHR+UI/hiAvYltf7gdCBHH95ZMPw +rvZmVyYSv1F+hVWVUEWNMP/L8QKBgQDj7jOscz75d9Wdr3f1YgtxumqHX0RyG4+c +b0g9XPT7g0i6Uovfvhq+TRxF1glMO47LuQ3AtGU/zN826i2X7vZbyR+BnpjmJ9ti +PMe721CQa4dE/UH4o/xBI9iyORgYaSSU6jjZLHXqcenCyPu4MDGej194baEKSKMA +AsZIyRhlQQKBgBnd+7dRCHtsrt3VQ3R1kECjh7mnGCrFi2KJYXI8lxChm8a3uJg2 +AUzup69+DO1/xDBomAPa7RSG7FbLUkvtS0AOKzxuUerL+9TY9lm/O9G19gk38niK +wGD8W/TeGXmg8dZ7dP552vNuhALOWVElrLB05368BiJ0euJCVUEc8ySRAoGAYjHa +3S6BMORpiRdxLKvilkpjXpKyYB5zjkd67cTAXiK/EFZDoE68IsQBrCx7sPXvnODK +hfyxqfzPJU9Z+Ryf0gchpav33x/IqdfZjJr9aFqK2jPpWf77y+xvjMiAEvQpKGaH +uzgmTKxqstn3Z/CLT+4giTdhq5aDcpu/ZNgNxIECgYAwHeuj1EVS5SRhpkbhgpgO +6SDnDN5lXTZwi0PKjSH6j2o5mf+5+BRAn17aatTTdyOOMaS/V7Fa0EECmrnGLWzT +Fi1VLavmtHg30FF9nDVXXbwAOSdwWle3vpaTvCiQQc0vGEtcwEwK75Vk6GfhAcSv +xYFy5ZN9gVX9/fO00Q7QCA== +-----END PRIVATE KEY----- diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java index 0be827ba..d42f0d3c 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacket.java @@ -26,11 +26,11 @@ protected void handleException(ByteBuffer buffer, Exception exception) { String hexDump; if (buffer.isDirect()) { - var array = new byte[buffer.limit()]; - buffer.get(array, 0, buffer.limit()); + var array = new byte[buffer.remaining()]; + buffer.get(array, buffer.position(), buffer.limit()); hexDump = hexDump(array, array.length); } else { - hexDump = hexDump(buffer.array(), buffer.limit()); + hexDump = hexDump(buffer.array(), buffer.position(), buffer.limit()); } log.warning(name(), buffer, hexDump, "[%s] -> buffer:[%s]\n[%s]"::formatted); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java index 2677c86c..567822a8 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketReader.java @@ -264,10 +264,10 @@ else if (packetFullLength > tempBigBuffer.capacity()) { } else { log.warning(remoteAddress, "[%s] Cannot create any instance of packet to read data"::formatted); } - - bufferToRead.position(endPosition); } + bufferToRead.position(endPosition); + if (bufferToRead.hasRemaining()) { if (bufferToRead == receivedBuffer) { pendingBuffer.put(receivedBuffer); @@ -360,7 +360,7 @@ protected void freeTempBigBuffers() { /** * Handles received data from the channel. */ - protected void handleReceivedData(Integer receivedBytes, ByteBuffer readingBuffer) { + protected void handleReceivedData(int receivedBytes, ByteBuffer readingBuffer) { updateActivityFunction.run(); if (receivedBytes == -1) { diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java index a4357a23..2b3b720c 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractReadableNetworkPacket.java @@ -22,11 +22,13 @@ public abstract class AbstractReadableNetworkPacket @Override public boolean read(ByteBuffer buffer, int remainingDataLength) { int oldLimit = buffer.limit(); + int oldPosition = buffer.position(); try { - buffer.limit(buffer.position() + remainingDataLength); + buffer.limit(oldPosition + remainingDataLength); readImpl(buffer); return true; } catch (Exception e) { + buffer.position(oldPosition); handleException(buffer, e); return false; } finally { diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java index 78199f79..8061c61c 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java @@ -2,27 +2,31 @@ import static javasabr.rlib.network.util.NetworkUtils.hexDump; -import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.util.function.Consumer; +import javasabr.rlib.common.util.BufferUtils; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.ReadableNetworkPacket; import javasabr.rlib.network.packet.WritableNetworkPacket; import javasabr.rlib.network.util.NetworkUtils; +import javasabr.rlib.network.util.SslUtils; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLException; import lombok.AccessLevel; import lombok.CustomLog; +import lombok.Getter; +import lombok.experimental.Accessors; import lombok.experimental.FieldDefaults; /** * @author JavaSaBr */ @CustomLog +@Accessors(fluent = true, chain = false) @FieldDefaults(level = AccessLevel.PROTECTED) public abstract class AbstractSslNetworkPacketReader> extends AbstractNetworkPacketReader { @@ -36,8 +40,12 @@ public abstract class AbstractSslNetworkPacketReader packetWriter; + @Getter(value = AccessLevel.PROTECTED) volatile ByteBuffer sslNetworkBuffer; + @Getter(value = AccessLevel.PROTECTED) volatile ByteBuffer sslDataBuffer; + @Getter(value = AccessLevel.PROTECTED) + volatile ByteBuffer sslDataPendingBuffer; protected AbstractSslNetworkPacketReader( C connection, @@ -53,40 +61,51 @@ protected AbstractSslNetworkPacketReader( this.sslDataBuffer = bufferAllocator.takeBuffer(sslEngine .getSession() .getApplicationBufferSize()); + this.sslDataPendingBuffer = bufferAllocator.takeBuffer(sslEngine + .getSession() + .getApplicationBufferSize() * 2); this.sslNetworkBuffer = bufferAllocator.takeBuffer(sslEngine .getSession() - .getPacketBufferSize()); + .getPacketBufferSize()) + .limit(0); this.packetWriter = packetWriter; } @Override - protected ByteBuffer bufferToReadFromChannel() { - return sslNetworkBuffer; - } - - @Override - protected void handleReceivedData(Integer receivedBytes, ByteBuffer readingBuffer) { + protected void handleReceivedData(int receivedBytes, ByteBuffer readingBuffer) { if (receivedBytes == -1) { - doHandshake(readingBuffer, -1); + doHandshake(sslNetworkBuffer(), -1); return; } super.handleReceivedData(receivedBytes, readingBuffer); } @Override - protected int readPackets(ByteBuffer receivedBuffer) { - var handshakeStatus = sslEngine.getHandshakeStatus(); - // ssl engine is ready to decrypt - if (handshakeStatus == HandshakeStatus.FINISHED || handshakeStatus == HandshakeStatus.NOT_HANDSHAKING) { - return decryptAndRead(receivedBuffer); + protected int readPackets(ByteBuffer readingBuffer) { + ByteBuffer networkBuffer = moveDataToNetworkBuffer(readingBuffer); + HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); + if (SslUtils.isReadyToDecrypt(handshakeStatus)) { + return decryptAndRead(networkBuffer); } else { - return doHandshake(receivedBuffer, receivedBuffer.limit()); + return doHandshake(networkBuffer, networkBuffer.limit()); } } + private ByteBuffer moveDataToNetworkBuffer(ByteBuffer readingBuffer) { + ByteBuffer sslNetworkBuffer = sslNetworkBuffer(); + int freeSpace = sslNetworkBuffer.capacity() - sslNetworkBuffer.limit(); + if (freeSpace >= readingBuffer.limit()) { + BufferUtils.appendAndClear(sslNetworkBuffer, readingBuffer); + } else { + sslNetworkBuffer = increaseNetworkBuffer(readingBuffer.limit()); + BufferUtils.appendAndClear(sslNetworkBuffer, readingBuffer); + } + return sslNetworkBuffer; + } + protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); - while (handshakeStatus != HandshakeStatus.FINISHED && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) { + while (SslUtils.needToProcess(handshakeStatus)) { log.debug(handshakeStatus, "Do handshake with status:[%s] "::formatted); SSLEngineResult result; switch (handshakeStatus) { @@ -105,7 +124,7 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { handshakeStatus = sslEngine.getHandshakeStatus(); break; } else if (!receivedBuffer.hasRemaining()) { - receivedBuffer.clear(); + receivedBuffer.clear().limit(0); return SKIP_READ_PACKETS; } try { @@ -121,15 +140,18 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { break; } switch (result.getStatus()) { - case OK: + case OK: { break; - case BUFFER_OVERFLOW: + } + case BUFFER_OVERFLOW: { throw new IllegalStateException("Unexpected ssl engine result"); - case BUFFER_UNDERFLOW: + } + case BUFFER_UNDERFLOW: { log.debug("Increase ssl network buffer"); - increaseNetworkBuffer(); + increaseNetworkBuffer(0); break; - case CLOSED: + } + case CLOSED: { if (sslEngine.isOutboundDone()) { return SKIP_READ_PACKETS; } else { @@ -137,15 +159,17 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { handshakeStatus = sslEngine.getHandshakeStatus(); break; } - default: + } + default: { throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + } } break; } case NEED_WRAP: { log.debug("Send command to wrap data"); packetWriter.accept(SslWritableNetworkPacket.getInstance()); - sslNetworkBuffer.clear(); + receivedBuffer.clear().limit(0); return SKIP_READ_PACKETS; } case NEED_TASK: { @@ -157,7 +181,7 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { handshakeStatus = sslEngine.getHandshakeStatus(); log.debug(handshakeStatus, "Handshake status:[%s] after engine tasks"::formatted); if (handshakeStatus == HandshakeStatus.NEED_UNWRAP && !receivedBuffer.hasRemaining()) { - sslNetworkBuffer.clear(); + receivedBuffer.clear().limit(0); return SKIP_READ_PACKETS; } break; @@ -173,7 +197,7 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { if (handshakeStatus == HandshakeStatus.FINISHED) { packetWriter.accept(SslWritableNetworkPacket.getInstance()); } - receivedBuffer.clear(); + receivedBuffer.clear().limit(0); return SKIP_READ_PACKETS; } @@ -194,13 +218,21 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { case OK: { sslDataBuffer.flip(); log.debug(sslDataBuffer, buf -> "Decrypted data:\n" + hexDump(buf)); - total += readPackets(sslDataBuffer, pendingBuffer); + total += readPackets(sslDataBuffer, sslDataPendingBuffer); break; } case BUFFER_OVERFLOW: { increaseDataBuffer(); return decryptAndRead(receivedBuffer); } + case BUFFER_UNDERFLOW: { + if (receivedBuffer.position() > 0) { + receivedBuffer + .compact() + .limit(receivedBuffer.position()); + } + return SKIP_READ_PACKETS; + } case CLOSED: { connection.close(); return SKIP_READ_PACKETS; @@ -219,17 +251,34 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { return total; } - private void increaseNetworkBuffer() { - sslNetworkBuffer = NetworkUtils.increasePacketBuffer(sslNetworkBuffer, bufferAllocator, sslEngine); + private synchronized ByteBuffer increaseNetworkBuffer(int extra) { + ByteBuffer current = sslNetworkBuffer(); + int newSize = (int) Math.max(current.capacity() * 1.3, current.capacity() + extra); + sslNetworkBuffer = NetworkUtils + .increaseBuffer(current, bufferAllocator, newSize) + .flip(); + return sslNetworkBuffer; } - private void increaseDataBuffer() { - sslDataBuffer = NetworkUtils.increaseApplicationBuffer(sslDataBuffer, bufferAllocator, sslEngine); + private synchronized void increaseDataBuffer() { + int newSize = sslEngine + .getSession() + .getApplicationBufferSize(); + sslDataBuffer = NetworkUtils + .increaseBuffer(sslDataBuffer, bufferAllocator, newSize) + .flip(); + sslDataPendingBuffer = NetworkUtils + .increaseBuffer(sslDataPendingBuffer, bufferAllocator, newSize * 2) + .flip(); } @Override public void close() { sslEngine.closeOutbound(); + bufferAllocator + .putBuffer(sslDataBuffer) + .putBuffer(sslDataPendingBuffer) + .putBuffer(sslNetworkBuffer); super.close(); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java index a896ef20..c74504a1 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java @@ -22,7 +22,11 @@ public class StringReadablePacket extends AbstractReadableNetworkPacket { @Override protected void readImpl(ByteBuffer buffer) { + readLong(buffer); + readLong(buffer); this.data = readString(buffer, MAX_LENGTH); + readLong(buffer); + readLong(buffer); } @Override diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java index e8c63323..9dbd8636 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java @@ -18,12 +18,16 @@ public class StringWritableNetworkPacket extends AbstractWritableNetworkPacket { @Override protected void writeImpl(ByteBuffer buffer) { super.writeImpl(buffer); + writeLong(buffer, 0); + writeLong(buffer, Long.MAX_VALUE); writeString(buffer, data); + writeLong(buffer, Long.MAX_VALUE); + writeLong(buffer, 0); } @Override public int expectedLength() { - return 4 + data.length() * 2; + return 32 + 4 + data.length() * 2; } @Override diff --git a/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java b/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java index a5b0bdd5..e2877f2c 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java @@ -166,14 +166,12 @@ public static String hexDump(byte[] array, int offset, int length) { hexDigit(builder, (byte) ((offset >>> 8) & 0xFF)); hexDigit(builder, (byte) (offset & 0xFF)); - builder.append(": "); + builder.append(": "); for (int i = offset; i < length; i++) { - byte val = array[i]; char ch; - if (val < ' ' || val > 'z') { ch = '.'; } else { @@ -181,45 +179,31 @@ public static String hexDump(byte[] array, int offset, int length) { } if (i == end) { - chars[count] = ch; - hexDigit(builder, val) .append(" ".repeat(15 - count)) .append(" "); - if (count < 9) { builder.append(" "); } - builder.append(chars); - } else if (count < 15) { - chars[count++] = ch; hexDigit(builder, val).append(' '); - if (count == 8) { builder.append(" "); } - } else { - chars[15] = ch; - hexDigit(builder, val) .append(" ") .append(chars) .append('\n'); - var nextPos = i + 1; - hexDigit(builder, (byte) ((nextPos >>> 8) & 0xFF)); hexDigit(builder, (byte) (nextPos & 0xFF)); builder.append(": "); - count = 0; - for (int g = 0; g < 16; g++) { chars[g] = '.'; } @@ -335,6 +319,18 @@ public static ByteBuffer increasePacketBuffer( return newBuffer; } + public static ByteBuffer increaseBuffer(ByteBuffer current, BufferAllocator allocator, int newSize) { + + var newBuffer = allocator.takeBuffer(newSize); + newBuffer.put(current); + + if (current.capacity() > 0) { + allocator.putBuffer(current); + } + + return newBuffer; + } + public static ByteBuffer enlargeApplicationBuffer( BufferAllocator allocator, SSLEngine engine) { diff --git a/rlib-network/src/main/java/javasabr/rlib/network/util/SslUtils.java b/rlib-network/src/main/java/javasabr/rlib/network/util/SslUtils.java new file mode 100644 index 00000000..5a4b93b6 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/util/SslUtils.java @@ -0,0 +1,16 @@ +package javasabr.rlib.network.util; + +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import lombok.experimental.UtilityClass; + +@UtilityClass +public class SslUtils { + + public static boolean isReadyToDecrypt(HandshakeStatus status) { + return status == HandshakeStatus.FINISHED || status == HandshakeStatus.NOT_HANDSHAKING; + } + + public static boolean needToProcess(HandshakeStatus status) { + return status != HandshakeStatus.FINISHED && status != HandshakeStatus.NOT_HANDSHAKING; + } +} From 6015fa8e96ae47cf38115c99183607c2fd456fad Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 5 Oct 2025 19:44:21 +0200 Subject: [PATCH 11/15] continue fix ssl network implementation --- .../network/StringSslNetworkLoadTest.java | 10 +- .../rlib/network/BufferAllocator.java | 1 + .../impl/AbstractNetworkPacketWriter.java | 36 +++-- .../impl/AbstractSslNetworkPacketReader.java | 47 ++++--- .../impl/AbstractSslNetworkPacketWriter.java | 130 +++++++++++------- .../packet/impl/StringReadablePacket.java | 2 + .../impl/StringWritableNetworkPacket.java | 4 +- .../rlib/network/util/NetworkUtils.java | 23 ---- .../javasabr/rlib/network/util/SslUtils.java | 10 +- 9 files changed, 150 insertions(+), 113 deletions(-) diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java index 55c0f834..02b62d41 100644 --- a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java @@ -82,7 +82,7 @@ void connectAndSendMessages( int delay = random.nextInt(MAX_SEND_DELAY); ScheduledFuture schedule = executor.schedule( () -> { - StringWritableNetworkPacket message = newMessage(10, 10240); // 10240 + StringWritableNetworkPacket message = newMessage(12000, 15000); // 10240 connection.send(message); }, delay, TimeUnit.MILLISECONDS); tasks.add(schedule); @@ -122,7 +122,7 @@ private static class StatisticsCollector { @SneakyThrows void testServerWithMultiplyClients() { LoggerManager.enable(StringSslNetworkLoadTest.class, LoggerLevel.INFO); - LoggerManager.enable(AbstractSslNetworkPacketReader.class, LoggerLevel.DEBUG); + //LoggerManager.enable(AbstractSslNetworkPacketReader.class, LoggerLevel.DEBUG); var serverConfig = SimpleServerNetworkConfig .builder() @@ -136,7 +136,7 @@ void testServerWithMultiplyClients() { ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); int clientCount = 1; - int messagesPerIteration = 300; + int messagesPerIteration = 20; int expectedMessages = clientCount * messagesPerIteration * MAX_ITERATIONS; var finalWaiter = new CountDownLatch(2); @@ -214,6 +214,8 @@ private static void initReceivedMessagesTracker( } private static StringWritableNetworkPacket newMessage(int minMessageLength, int maxMessageLength) { - return new StringWritableNetworkPacket(StringUtils.generate(minMessageLength, maxMessageLength)); + String generate = StringUtils.generate(minMessageLength, maxMessageLength); + return new StringWritableNetworkPacket("a".repeat(generate.length())); + //return new StringWritableNetworkPacket(StringUtils.generate(minMessageLength, maxMessageLength)); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/BufferAllocator.java b/rlib-network/src/main/java/javasabr/rlib/network/BufferAllocator.java index d713c3f1..0bcbfc99 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/BufferAllocator.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/BufferAllocator.java @@ -1,6 +1,7 @@ package javasabr.rlib.network; import java.nio.ByteBuffer; +import org.jspecify.annotations.Nullable; /** * The interface to implement a buffer allocator for network things. diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java index d0198e2f..7b6c899f 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java @@ -4,6 +4,7 @@ import static javasabr.rlib.network.util.NetworkUtils.hexDump; import java.io.IOException; +import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; @@ -116,7 +117,6 @@ public boolean tryToSendNextPacket() { } serializedToChannelPacketHandler.accept(nextPacket); - return startedWriting; } @@ -143,9 +143,25 @@ protected ByteBuffer serialize(WritableNetworkPacket packet) { ByteBuffer second = bufferAllocator.takeBuffer(totalSize); firstWriteTempBuffer = first; secondWriteTempBuffer = second; - return serialize(resultPacket, expectedLength, totalSize, first, second); + try { + return serialize(resultPacket, expectedLength, totalSize, first, second); + } catch (BufferOverflowException ex) { + log.error(ex); + bufferAllocator.putBuffer(first); + bufferAllocator.putBuffer(second); + firstWriteTempBuffer = null; + secondWriteTempBuffer = null; + throw new RuntimeException(ex); + } } else { - return serialize(resultPacket, expectedLength, totalSize, firstWriteBuffer, secondWriteBuffer); + try { + return serialize(resultPacket, expectedLength, totalSize, firstWriteBuffer, secondWriteBuffer); + } catch (BufferOverflowException ex) { + log.error(ex); + firstWriteBuffer.clear(); + secondWriteBuffer.clear(); + throw new RuntimeException(ex); + } } } @@ -359,29 +375,25 @@ protected void handleFailedWritingData(Throwable exception, WritableNetworkPacke @Override public void close() { - bufferAllocator .putWriteBuffer(firstWriteBuffer) .putWriteBuffer(secondWriteBuffer); - clearTempBuffers(); - writingBuffer = EMPTY_BUFFER; } protected void clearTempBuffers() { - var secondWriteTempBuffer = this.secondWriteTempBuffer; var firstWriteTempBuffer = this.firstWriteTempBuffer; + if (firstWriteTempBuffer != null) { + this.firstWriteTempBuffer = null; + bufferAllocator.putBuffer(firstWriteTempBuffer); + } + var secondWriteTempBuffer = this.secondWriteTempBuffer; if (secondWriteTempBuffer != null) { this.secondWriteTempBuffer = null; bufferAllocator.putBuffer(secondWriteTempBuffer); } - - if (firstWriteTempBuffer != null) { - this.firstWriteTempBuffer = null; - bufferAllocator.putBuffer(firstWriteTempBuffer); - } } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java index 8061c61c..54d0f2e5 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java @@ -84,17 +84,17 @@ protected void handleReceivedData(int receivedBytes, ByteBuffer readingBuffer) { protected int readPackets(ByteBuffer readingBuffer) { ByteBuffer networkBuffer = moveDataToNetworkBuffer(readingBuffer); HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); - if (SslUtils.isReadyToDecrypt(handshakeStatus)) { + if (SslUtils.isReadyToCrypt(handshakeStatus)) { return decryptAndRead(networkBuffer); } else { return doHandshake(networkBuffer, networkBuffer.limit()); } } - private ByteBuffer moveDataToNetworkBuffer(ByteBuffer readingBuffer) { + protected ByteBuffer moveDataToNetworkBuffer(ByteBuffer readingBuffer) { ByteBuffer sslNetworkBuffer = sslNetworkBuffer(); - int freeSpace = sslNetworkBuffer.capacity() - sslNetworkBuffer.limit(); - if (freeSpace >= readingBuffer.limit()) { + int availableSpace = sslNetworkBuffer.capacity() - sslNetworkBuffer.limit(); + if (availableSpace >= readingBuffer.limit()) { BufferUtils.appendAndClear(sslNetworkBuffer, readingBuffer); } else { sslNetworkBuffer = increaseNetworkBuffer(readingBuffer.limit()); @@ -103,7 +103,7 @@ private ByteBuffer moveDataToNetworkBuffer(ByteBuffer readingBuffer) { return sslNetworkBuffer; } - protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { + protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); while (SslUtils.needToProcess(handshakeStatus)) { log.debug(handshakeStatus, "Do handshake with status:[%s] "::formatted); @@ -123,13 +123,13 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { sslEngine.closeOutbound(); handshakeStatus = sslEngine.getHandshakeStatus(); break; - } else if (!receivedBuffer.hasRemaining()) { - receivedBuffer.clear().limit(0); + } else if (!networkBuffer.hasRemaining()) { + cleanNetworkBuffer(networkBuffer); return SKIP_READ_PACKETS; } try { - log.debug(receivedBuffer, buff -> "Try to unwrap data:\n" + hexDump(buff)); - result = sslEngine.unwrap(receivedBuffer, EMPTY_BUFFERS); + log.debug(networkBuffer, buff -> "Try to unwrap data:\n" + hexDump(buff)); + result = sslEngine.unwrap(networkBuffer, EMPTY_BUFFERS); handshakeStatus = result.getHandshakeStatus(); log.debug(handshakeStatus, "Handshake status:[%s] after unwrapping"::formatted); } catch (SSLException sslException) { @@ -167,21 +167,16 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { break; } case NEED_WRAP: { - log.debug("Send command to wrap data"); + log.debug(remoteAddress(), "[%s] Send command to wrap data"::formatted); packetWriter.accept(SslWritableNetworkPacket.getInstance()); - receivedBuffer.clear().limit(0); + cleanNetworkBuffer(networkBuffer); return SKIP_READ_PACKETS; } case NEED_TASK: { - Runnable task; - while ((task = sslEngine.getDelegatedTask()) != null) { - log.debug(task, "Execute SSL Engine's task:[%s]"::formatted); - task.run(); - } - handshakeStatus = sslEngine.getHandshakeStatus(); + handshakeStatus = SslUtils.executeSslTasks(sslEngine); log.debug(handshakeStatus, "Handshake status:[%s] after engine tasks"::formatted); - if (handshakeStatus == HandshakeStatus.NEED_UNWRAP && !receivedBuffer.hasRemaining()) { - receivedBuffer.clear().limit(0); + if (handshakeStatus == HandshakeStatus.NEED_UNWRAP && !networkBuffer.hasRemaining()) { + cleanNetworkBuffer(networkBuffer); return SKIP_READ_PACKETS; } break; @@ -192,16 +187,16 @@ protected int doHandshake(ByteBuffer receivedBuffer, int receivedBytes) { } } - if (!receivedBuffer.hasRemaining()) { + if (!networkBuffer.hasRemaining()) { // if buffer is empty and status is FINISHED then we can notify writer if (handshakeStatus == HandshakeStatus.FINISHED) { packetWriter.accept(SslWritableNetworkPacket.getInstance()); } - receivedBuffer.clear().limit(0); + cleanNetworkBuffer(networkBuffer); return SKIP_READ_PACKETS; } - return decryptAndRead(receivedBuffer); + return decryptAndRead(networkBuffer); } protected int decryptAndRead(ByteBuffer receivedBuffer) { @@ -251,7 +246,7 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { return total; } - private synchronized ByteBuffer increaseNetworkBuffer(int extra) { + protected synchronized ByteBuffer increaseNetworkBuffer(int extra) { ByteBuffer current = sslNetworkBuffer(); int newSize = (int) Math.max(current.capacity() * 1.3, current.capacity() + extra); sslNetworkBuffer = NetworkUtils @@ -260,7 +255,7 @@ private synchronized ByteBuffer increaseNetworkBuffer(int extra) { return sslNetworkBuffer; } - private synchronized void increaseDataBuffer() { + protected synchronized void increaseDataBuffer() { int newSize = sslEngine .getSession() .getApplicationBufferSize(); @@ -281,4 +276,8 @@ public void close() { .putBuffer(sslNetworkBuffer); super.close(); } + + protected static void cleanNetworkBuffer(ByteBuffer networkBuffer) { + networkBuffer.clear().limit(0); + } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java index 1d5f37ee..3018d90e 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java @@ -3,10 +3,8 @@ import static javasabr.rlib.network.util.NetworkUtils.EMPTY_BUFFER; import static javasabr.rlib.network.util.NetworkUtils.hexDump; -import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; import javasabr.rlib.functions.ObjBoolConsumer; @@ -14,16 +12,20 @@ import javasabr.rlib.network.Connection; import javasabr.rlib.network.packet.WritableNetworkPacket; import javasabr.rlib.network.util.NetworkUtils; +import javasabr.rlib.network.util.SslUtils; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLException; import lombok.AccessLevel; import lombok.CustomLog; +import lombok.Getter; +import lombok.experimental.Accessors; import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; @CustomLog +@Accessors(fluent = true, chain = false) @FieldDefaults(level = AccessLevel.PROTECTED) public abstract class AbstractSslNetworkPacketWriter> extends AbstractNetworkPacketWriter { @@ -35,7 +37,12 @@ public abstract class AbstractSslNetworkPacketWriter queueAtFirst; - protected volatile ByteBuffer sslNetworkBuffer; + @Getter(AccessLevel.PROTECTED) + @Nullable + volatile ByteBuffer sslTempBuffer; + + @Getter(AccessLevel.PROTECTED) + volatile ByteBuffer sslNetworkBuffer; public AbstractSslNetworkPacketWriter( C connection, @@ -74,57 +81,79 @@ public boolean tryToSendNextPacket() { @Override protected ByteBuffer serialize(WritableNetworkPacket packet) { HandshakeStatus status = sslEngine.getHandshakeStatus(); - if (status == HandshakeStatus.FINISHED || status == HandshakeStatus.NOT_HANDSHAKING) { + if (SslUtils.isReadyToCrypt(status)) { if (packet instanceof SslWritableNetworkPacket) { return EMPTY_BUFFER; } - ByteBuffer packetDataBuffer = super.serialize(packet); - log.debug(packetDataBuffer, buff -> "Try to encrypt data:\n" + hexDump(buff)); + ByteBuffer serialized = super.serialize(packet); - SSLEngineResult result; - try { - result = sslEngine.wrap(packetDataBuffer, sslNetworkBuffer.clear()); - } catch (SSLException e) { - throw new RuntimeException(e); - } + log.debug(remoteAddress(), serialized, (address, buff) -> + "[%s] Try to encrypt data:\n%s".formatted(address, hexDump(buff))); - switch (result.getStatus()) { - case BUFFER_UNDERFLOW: { - increaseNetworkBuffer(); - break; - } - case BUFFER_OVERFLOW: { - throw new IllegalStateException("Unexpected ssl engine result"); - } - case OK: { - return sslNetworkBuffer.flip(); - } - case CLOSED: { - closeConnection(); - return EMPTY_BUFFER; + ByteBuffer bufferToSend = sslNetworkBuffer(); + SSLEngineResult result = tryEncrypt(serialized, bufferToSend); + + if (result.getStatus() == SSLEngineResult.Status.OK && serialized.hasRemaining()) { + int tempBufferSize = (int) ((bufferToSend.limit() + serialized.remaining()) * 1.2); + ByteBuffer tempBuffer = bufferAllocator.takeBuffer(tempBufferSize); + tempBuffer.put(bufferToSend.flip()); + while (serialized.hasRemaining()) { + result = tryEncrypt(serialized, bufferToSend); + if (result.getStatus() != SSLEngineResult.Status.OK) { + break; + } + tempBuffer.put(bufferToSend.flip()); } + bufferToSend = tempBuffer; + this.sslTempBuffer = tempBuffer; } + + return switch (result.getStatus()) { + case BUFFER_UNDERFLOW -> increaseAndTryAgain(packet); + case BUFFER_OVERFLOW -> throw new IllegalStateException("Unexpected ssl engine result"); + case OK -> bufferToSend.flip(); + case CLOSED -> closeAndReturn(); + }; } - ByteBuffer bufferToWrite = doHandshake(packet); - if (bufferToWrite != null) { - return bufferToWrite; + ByteBuffer dataToSend = doHandshake(packet); + if (dataToSend != null) { + return dataToSend; } throw new IllegalStateException(); } + protected ByteBuffer closeAndReturn() { + connection.close(); + return EMPTY_BUFFER; + } + + protected ByteBuffer increaseAndTryAgain(WritableNetworkPacket packet) { + log.debug(remoteAddress(), "[%s] Increase network buffer and try again..."::formatted); + increaseNetworkBuffer(); + return serialize(packet); + } + + protected SSLEngineResult tryEncrypt(ByteBuffer source, ByteBuffer destination) { + try { + return sslEngine.wrap(source, destination.clear()); + } catch (SSLException ex) { + log.error(ex); + throw new RuntimeException(ex); + } + } + @Nullable protected ByteBuffer doHandshake(WritableNetworkPacket packet) { if (!(packet instanceof SslWritableNetworkPacket)) { - log.debug(packet, "Return packet:[%s] to queue as first"::formatted); + log.debug(remoteAddress(), packet, "[%s] Return packet:[%s] to queue as first"::formatted); queueAtFirst.accept(packet); } HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); - - while (handshakeStatus != HandshakeStatus.FINISHED && handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) { + while (SslUtils.needToProcess(handshakeStatus)) { SSLEngineResult result; switch (handshakeStatus) { case NEED_WRAP: { @@ -149,7 +178,8 @@ protected ByteBuffer doHandshake(WritableNetworkPacket packet) { log.debug(sslNetworkBuffer, result, (buf, res) -> "Send wrapped data:\n" + hexDump(buf, res)); return sslNetworkBuffer; case BUFFER_OVERFLOW: { - sslNetworkBuffer = NetworkUtils.enlargePacketBuffer(bufferAllocator, sslEngine); + log.debug(remoteAddress(), "[%s] Increase network buffer"::formatted); + increaseNetworkBuffer(); break; } case BUFFER_UNDERFLOW: { @@ -171,12 +201,7 @@ protected ByteBuffer doHandshake(WritableNetworkPacket packet) { break; } case NEED_TASK: { - Runnable task; - while ((task = sslEngine.getDelegatedTask()) != null) { - log.debug(task, "Execute SSL Engine's task:[%s]"::formatted); - task.run(); - } - handshakeStatus = sslEngine.getHandshakeStatus(); + handshakeStatus = SslUtils.executeSslTasks(sslEngine); break; } case NEED_UNWRAP: { @@ -191,16 +216,25 @@ protected ByteBuffer doHandshake(WritableNetworkPacket packet) { return EMPTY_BUFFER; } - private void increaseNetworkBuffer() { - sslNetworkBuffer = NetworkUtils.increasePacketBuffer(sslNetworkBuffer, bufferAllocator, sslEngine); + @Override + protected void clearTempBuffers() { + super.clearTempBuffers(); + ByteBuffer sslTempBuffer = this.sslTempBuffer; + if (sslTempBuffer != null) { + bufferAllocator.putBuffer(sslTempBuffer); + this.sslTempBuffer = null; + } } - protected void closeConnection() { - try { - sslEngine.closeOutbound(); - socketChannel.close(); - } catch (IOException e) { - throw new RuntimeException(e); - } + protected synchronized void increaseNetworkBuffer() { + sslNetworkBuffer = NetworkUtils + .increasePacketBuffer(sslNetworkBuffer, bufferAllocator, sslEngine); + } + + @Override + public void close() { + sslEngine.closeOutbound(); + bufferAllocator.putBuffer(sslNetworkBuffer); + super.close(); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java index c74504a1..ce25eac2 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java @@ -22,11 +22,13 @@ public class StringReadablePacket extends AbstractReadableNetworkPacket { @Override protected void readImpl(ByteBuffer buffer) { + readLong(buffer); readLong(buffer); readLong(buffer); this.data = readString(buffer, MAX_LENGTH); readLong(buffer); readLong(buffer); + readLong(buffer); } @Override diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java index 9dbd8636..524685db 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java @@ -20,14 +20,16 @@ protected void writeImpl(ByteBuffer buffer) { super.writeImpl(buffer); writeLong(buffer, 0); writeLong(buffer, Long.MAX_VALUE); + writeLong(buffer, Long.MAX_VALUE); writeString(buffer, data); writeLong(buffer, Long.MAX_VALUE); writeLong(buffer, 0); + writeLong(buffer, 0); } @Override public int expectedLength() { - return 32 + 4 + data.length() * 2; + return 48 + 4 + data.length() * 2; } @Override diff --git a/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java b/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java index e2877f2c..01dd27c0 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java @@ -279,29 +279,6 @@ public static int getAvailablePort(int port) { .orElse(-1); } - public static ByteBuffer enlargePacketBuffer(BufferAllocator allocator, SSLEngine engine) { - return allocator.takeBuffer(engine - .getSession() - .getPacketBufferSize()); - } - - public static ByteBuffer increaseApplicationBuffer( - ByteBuffer current, - BufferAllocator allocator, - SSLEngine engine) { - - var newBuffer = allocator.takeBuffer(engine - .getSession() - .getApplicationBufferSize()); - newBuffer.put(current); - - if (current.capacity() > 0) { - allocator.putBuffer(current); - } - - return newBuffer; - } - public static ByteBuffer increasePacketBuffer( ByteBuffer current, BufferAllocator allocator, diff --git a/rlib-network/src/main/java/javasabr/rlib/network/util/SslUtils.java b/rlib-network/src/main/java/javasabr/rlib/network/util/SslUtils.java index 5a4b93b6..45917c19 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/util/SslUtils.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/util/SslUtils.java @@ -1,16 +1,24 @@ package javasabr.rlib.network.util; +import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import lombok.experimental.UtilityClass; @UtilityClass public class SslUtils { - public static boolean isReadyToDecrypt(HandshakeStatus status) { + public static boolean isReadyToCrypt(HandshakeStatus status) { return status == HandshakeStatus.FINISHED || status == HandshakeStatus.NOT_HANDSHAKING; } public static boolean needToProcess(HandshakeStatus status) { return status != HandshakeStatus.FINISHED && status != HandshakeStatus.NOT_HANDSHAKING; } + + public static HandshakeStatus executeSslTasks(SSLEngine engine) { + for (Runnable task = engine.getDelegatedTask(); task != null; task = engine.getDelegatedTask()) { + task.run(); + } + return engine.getHandshakeStatus(); + } } From b5bc8f9103a307f7c5911627ea858e5a0e43fb22 Mon Sep 17 00:00:00 2001 From: javasabr Date: Sun, 5 Oct 2025 21:19:08 +0200 Subject: [PATCH 12/15] continue fix ssl network implementation --- .../network/StringSslNetworkLoadTest.java | 2 +- .../network/packet/WritableNetworkPacket.java | 1 + .../impl/AbstractNetworkPacketWriter.java | 74 ++++++++++++------- .../impl/AbstractSslNetworkPacketWriter.java | 21 +++++- 4 files changed, 66 insertions(+), 32 deletions(-) diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java index 02b62d41..c5afe263 100644 --- a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java @@ -82,7 +82,7 @@ void connectAndSendMessages( int delay = random.nextInt(MAX_SEND_DELAY); ScheduledFuture schedule = executor.schedule( () -> { - StringWritableNetworkPacket message = newMessage(12000, 15000); // 10240 + StringWritableNetworkPacket message = newMessage(10, 100); // 10240 connection.send(message); }, delay, TimeUnit.MILLISECONDS); tasks.add(schedule); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/WritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/WritableNetworkPacket.java index d966e82b..91b997b6 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/WritableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/WritableNetworkPacket.java @@ -2,6 +2,7 @@ import java.nio.ByteBuffer; + /** * Interface to implement a writable packet. * diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java index 7b6c899f..d2660ea7 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractNetworkPacketWriter.java @@ -34,15 +34,15 @@ public abstract class AbstractNetworkPacketWriter> implements NetworkPacketWriter { - final CompletionHandler writeHandler = new CompletionHandler<>() { + final CompletionHandler writeHandler = new CompletionHandler<>() { @Override - public void completed(Integer result, WritableNetworkPacket packet) { + public void completed(Integer result, @Nullable WritableNetworkPacket packet) { handleSuccessfulWritingData(result, packet); } @Override - public void failed(Throwable exc, WritableNetworkPacket packet) { + public void failed(Throwable exc, @Nullable WritableNetworkPacket packet) { handleFailedWritingData(exc, packet); } }; @@ -64,7 +64,7 @@ public void failed(Throwable exc, WritableNetworkPacket packet) { volatile ByteBuffer writingBuffer = EMPTY_BUFFER; final Runnable updateActivityFunction; - final Supplier<@Nullable WritableNetworkPacket> nextWritePacketSupplier; + final Supplier<@Nullable WritableNetworkPacket> writablePacketProvider; final ObjBoolConsumer sentPacketHandler; final Consumer serializedToChannelPacketHandler; @@ -82,7 +82,7 @@ public AbstractNetworkPacketWriter( this.firstWriteBuffer = bufferAllocator.takeWriteBuffer(); this.secondWriteBuffer = bufferAllocator.takeWriteBuffer(); this.updateActivityFunction = updateActivityFunction; - this.nextWritePacketSupplier = packetProvider; + this.writablePacketProvider = packetProvider; this.serializedToChannelPacketHandler = serializedToChannelPacketHandler; this.sentPacketHandler = sentPacketHandler; } @@ -97,29 +97,44 @@ public boolean tryToSendNextPacket() { return false; } - WritableNetworkPacket nextPacket = nextWritePacketSupplier.get(); - if (nextPacket == null) { - writing.set(false); - return false; + boolean startedWriting = false; + + try { + startedWriting = tryToSendNextPacketImpl(); + } catch (Exception ex) { + log.error(ex); } - boolean startedWriting = false; - ByteBuffer resultBuffer = serialize(nextPacket); - - if (resultBuffer.limit() != 0) { - writingBuffer = resultBuffer; - log.debug(remoteAddress(), resultBuffer, - (address, buff) -> "[%s] Write to channel data:\n" + hexDump(buff)); - socketChannel.write(resultBuffer, nextPacket, writeHandler); - startedWriting = true; - } else { + if (!startedWriting) { writing.set(false); } - serializedToChannelPacketHandler.accept(nextPacket); return startedWriting; } + protected boolean tryToSendNextPacketImpl() { + for (var nextPacket = writablePacketProvider.get(); + nextPacket != null; nextPacket = writablePacketProvider.get()) { + ByteBuffer resultBuffer = serialize(nextPacket); + boolean startedWriting = writeBuffer(resultBuffer, nextPacket); + serializedToChannelPacketHandler.accept(nextPacket); + if (startedWriting) { + return true; + } + } + return false; + } + + protected boolean writeBuffer(ByteBuffer resultBuffer, @Nullable WritableNetworkPacket nextPacket) { + if (resultBuffer.limit() == 0) { + return false; + } + writingBuffer = resultBuffer; + log.debug(remoteAddress(), resultBuffer, (address, buff) -> "[%s] Write to channel data:\n" + hexDump(buff)); + socketChannel.write(resultBuffer, nextPacket, writeHandler); + return true; + } + /** * Serializes the network packet to buffer. * @@ -324,11 +339,13 @@ protected ByteBuffer writeHeader(ByteBuffer buffer, int value, int headerSize) { * @param wroteBytes the count of wrote bytes. * @param packet the sent packet. */ - protected void handleSuccessfulWritingData(Integer wroteBytes, WritableNetworkPacket packet) { + protected void handleSuccessfulWritingData(Integer wroteBytes, @Nullable WritableNetworkPacket packet) { updateActivityFunction.run(); if (wroteBytes == -1) { - sentPacketHandler.accept(packet, false); + if (packet != null) { + sentPacketHandler.accept(packet, false); + } connection.close(); return; } @@ -343,13 +360,12 @@ protected void handleSuccessfulWritingData(Integer wroteBytes, WritableNetworkPa log.debug(remoteAddress(), wroteBytes, "[%s] Finished writing [%s] bytes"::formatted); } - sentPacketHandler.accept(packet, true); + if (packet != null) { + sentPacketHandler.accept(packet, true); + } if (writing.compareAndSet(true, false)) { - // if we have temp buffers, we can remove it after finishing writing a packet - if (firstWriteTempBuffer != null || secondWriteTempBuffer != null) { - clearTempBuffers(); - } + clearTempBuffers(); tryToSendNextPacket(); } } @@ -360,7 +376,7 @@ protected void handleSuccessfulWritingData(Integer wroteBytes, WritableNetworkPa * @param exception the exception. * @param packet the packet. */ - protected void handleFailedWritingData(Throwable exception, WritableNetworkPacket packet) { + protected void handleFailedWritingData(Throwable exception, @Nullable WritableNetworkPacket packet) { log.error(new RuntimeException("Failed writing packet:" + packet, exception)); if (exception instanceof IOException) { connection.close(); @@ -368,6 +384,7 @@ protected void handleFailedWritingData(Throwable exception, WritableNetworkPacke } if (!connection.closed()) { if (writing.compareAndSet(true, false)) { + clearTempBuffers(); tryToSendNextPacket(); } } @@ -383,6 +400,7 @@ public void close() { } protected void clearTempBuffers() { + this.writingBuffer = EMPTY_BUFFER; var firstWriteTempBuffer = this.firstWriteTempBuffer; if (firstWriteTempBuffer != null) { diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java index 3018d90e..dc197d5f 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java @@ -78,6 +78,21 @@ public boolean tryToSendNextPacket() { return super.tryToSendNextPacket(); } + @Override + protected boolean tryToSendNextPacketImpl() { + HandshakeStatus status = sslEngine.getHandshakeStatus(); + if (SslUtils.isReadyToCrypt(status)) { + return super.tryToSendNextPacketImpl(); + } + + ByteBuffer dataToSend = doHandshake(SslWritableNetworkPacket.getInstance()); + if (dataToSend != null) { + return writeBuffer(dataToSend, null); + } + + throw new IllegalStateException("Unexpected SSL state"); + } + @Override protected ByteBuffer serialize(WritableNetworkPacket packet) { HandshakeStatus status = sslEngine.getHandshakeStatus(); @@ -158,7 +173,6 @@ protected ByteBuffer doHandshake(WritableNetworkPacket packet) { switch (handshakeStatus) { case NEED_WRAP: { try { - // check result result = sslEngine.wrap(EMPTY_BUFFERS, sslNetworkBuffer.clear()); handshakeStatus = result.getHandshakeStatus(); } catch (SSLException sslException) { @@ -168,13 +182,14 @@ protected ByteBuffer doHandshake(WritableNetworkPacket packet) { handshakeStatus = sslEngine.getHandshakeStatus(); break; } + switch (result.getStatus()) { case OK: sslNetworkBuffer.flip(); - if (handshakeStatus == HandshakeStatus.NEED_WRAP) { +/* if (handshakeStatus == HandshakeStatus.NEED_WRAP) { log.debug("Send command to wrap data again"); queueAtFirst.accept(SslWritableNetworkPacket.getInstance()); - } + }*/ log.debug(sslNetworkBuffer, result, (buf, res) -> "Send wrapped data:\n" + hexDump(buf, res)); return sslNetworkBuffer; case BUFFER_OVERFLOW: { From f6a8e8ff1e5f95b2f1fd7b3a66fc902c94059f28 Mon Sep 17 00:00:00 2001 From: javasabr Date: Mon, 6 Oct 2025 18:19:48 +0200 Subject: [PATCH 13/15] stabilize ssl implementation --- .../network/StringSslNetworkLoadTest.java | 10 ++- .../impl/AbstractSslNetworkPacketReader.java | 40 +++++---- .../impl/AbstractSslNetworkPacketWriter.java | 85 +++++++------------ 3 files changed, 63 insertions(+), 72 deletions(-) diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java index c5afe263..665b54a9 100644 --- a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java @@ -22,6 +22,7 @@ import javasabr.rlib.network.impl.StringDataConnection; import javasabr.rlib.network.impl.StringDataSslConnection; import javasabr.rlib.network.packet.impl.AbstractSslNetworkPacketReader; +import javasabr.rlib.network.packet.impl.AbstractSslNetworkPacketWriter; import javasabr.rlib.network.packet.impl.StringWritableNetworkPacket; import javasabr.rlib.network.server.ServerNetwork; import javasabr.rlib.network.util.NetworkUtils; @@ -82,7 +83,7 @@ void connectAndSendMessages( int delay = random.nextInt(MAX_SEND_DELAY); ScheduledFuture schedule = executor.schedule( () -> { - StringWritableNetworkPacket message = newMessage(10, 100); // 10240 + StringWritableNetworkPacket message = newMessage(10, 10240); // 10240 connection.send(message); }, delay, TimeUnit.MILLISECONDS); tasks.add(schedule); @@ -123,6 +124,7 @@ private static class StatisticsCollector { void testServerWithMultiplyClients() { LoggerManager.enable(StringSslNetworkLoadTest.class, LoggerLevel.INFO); //LoggerManager.enable(AbstractSslNetworkPacketReader.class, LoggerLevel.DEBUG); + //LoggerManager.enable(AbstractSslNetworkPacketWriter.class, LoggerLevel.DEBUG); var serverConfig = SimpleServerNetworkConfig .builder() @@ -135,8 +137,8 @@ void testServerWithMultiplyClients() { var serverAllocator = new DefaultBufferAllocator(serverConfig); ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); - int clientCount = 1; - int messagesPerIteration = 20; + int clientCount = 100; + int messagesPerIteration = 2000; int expectedMessages = clientCount * messagesPerIteration * MAX_ITERATIONS; var finalWaiter = new CountDownLatch(2); @@ -154,7 +156,7 @@ void testServerWithMultiplyClients() { statistics .receivedClientPackersPerSecond() .accumulate(1); - //connection.send(new StringWritableNetworkPacket("Echo: " + packet.data())); + connection.send(new StringWritableNetworkPacket("Echo: " + packet.data())); statistics .sentEchoPackersPerSecond() .accumulate(1); diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java index 54d0f2e5..b1acd19c 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java @@ -92,6 +92,8 @@ protected int readPackets(ByteBuffer readingBuffer) { } protected ByteBuffer moveDataToNetworkBuffer(ByteBuffer readingBuffer) { + log.debug(remoteAddress(), readingBuffer, + (address, buf) -> "[%s] Append new part of received data:\n%s".formatted(address, hexDump(buf))); ByteBuffer sslNetworkBuffer = sslNetworkBuffer(); int availableSpace = sslNetworkBuffer.capacity() - sslNetworkBuffer.limit(); if (availableSpace >= readingBuffer.limit()) { @@ -100,16 +102,18 @@ protected ByteBuffer moveDataToNetworkBuffer(ByteBuffer readingBuffer) { sslNetworkBuffer = increaseNetworkBuffer(readingBuffer.limit()); BufferUtils.appendAndClear(sslNetworkBuffer, readingBuffer); } + log.debug(remoteAddress(), sslNetworkBuffer, + (address, buf) -> "[%s] Result pending received network data:\n%s".formatted(address, hexDump(buf))); return sslNetworkBuffer; } protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); while (SslUtils.needToProcess(handshakeStatus)) { - log.debug(handshakeStatus, "Do handshake with status:[%s] "::formatted); - SSLEngineResult result; + log.debug(remoteAddress(), handshakeStatus, "[%s] Do handshake with status:[%s] "::formatted); switch (handshakeStatus) { case NEED_UNWRAP: { + SSLEngineResult result; if (receivedBytes == -1) { if (sslEngine.isInboundDone() && sslEngine.isOutboundDone()) { return SKIP_READ_PACKETS; @@ -128,10 +132,11 @@ protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { return SKIP_READ_PACKETS; } try { - log.debug(networkBuffer, buff -> "Try to unwrap data:\n" + hexDump(buff)); + log.debug(remoteAddress(), networkBuffer, + (address, buff) -> "[%s] Try to unwrap data:\n%s".formatted(address, hexDump(buff))); result = sslEngine.unwrap(networkBuffer, EMPTY_BUFFERS); handshakeStatus = result.getHandshakeStatus(); - log.debug(handshakeStatus, "Handshake status:[%s] after unwrapping"::formatted); + log.debug(remoteAddress(), handshakeStatus, "[%s] Handshake status:[%s] after unwrapping"::formatted); } catch (SSLException sslException) { log.error("A problem was encountered while processing the data that caused the " + "SSLEngine to abort. Will try to properly close connection..."); @@ -147,9 +152,13 @@ protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { throw new IllegalStateException("Unexpected ssl engine result"); } case BUFFER_UNDERFLOW: { - log.debug("Increase ssl network buffer"); - increaseNetworkBuffer(0); - break; + log.debug(remoteAddress(), "[%s] Wait for more received data..."::formatted); + if (networkBuffer.position() > 0) { + networkBuffer + .compact() + .limit(networkBuffer.position()); + } + return SKIP_READ_PACKETS; } case CLOSED: { if (sslEngine.isOutboundDone()) { @@ -174,7 +183,7 @@ protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { } case NEED_TASK: { handshakeStatus = SslUtils.executeSslTasks(sslEngine); - log.debug(handshakeStatus, "Handshake status:[%s] after engine tasks"::formatted); + log.debug(remoteAddress(), handshakeStatus, "[%s] Handshake status:[%s] after engine tasks"::formatted); if (handshakeStatus == HandshakeStatus.NEED_UNWRAP && !networkBuffer.hasRemaining()) { cleanNetworkBuffer(networkBuffer); return SKIP_READ_PACKETS; @@ -204,7 +213,8 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { while (receivedBuffer.hasRemaining()) { SSLEngineResult result; try { - log.debug(receivedBuffer, buf -> "Try to decrypt data:\n" + hexDump(buf)); + log.debug(remoteAddress(), receivedBuffer, + (address, buf) -> "[%s] Try to decrypt data:\n%s".formatted(address, hexDump(buf))); result = sslEngine.unwrap(receivedBuffer, sslDataBuffer.clear()); } catch (SSLException e) { throw new IllegalStateException(e); @@ -212,15 +222,18 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { switch (result.getStatus()) { case OK: { sslDataBuffer.flip(); - log.debug(sslDataBuffer, buf -> "Decrypted data:\n" + hexDump(buf)); + log.debug(remoteAddress(), sslDataBuffer, + (address, buf) -> "[%s] Decrypted data:\n%s".formatted(address, hexDump(buf))); total += readPackets(sslDataBuffer, sslDataPendingBuffer); break; } case BUFFER_OVERFLOW: { + log.debug(remoteAddress(), "Increase SSL data buffer and try again..."::formatted); increaseDataBuffer(); return decryptAndRead(receivedBuffer); } case BUFFER_UNDERFLOW: { + log.debug(remoteAddress(), "[%s] Wait for more received data..."::formatted); if (receivedBuffer.position() > 0) { receivedBuffer .compact() @@ -233,16 +246,13 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { return SKIP_READ_PACKETS; } default: { - if (receivedBuffer.position() > 0) { - receivedBuffer.compact(); - return total; - } throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); } } } - receivedBuffer.clear(); + log.debug(remoteAddress(), "[%s] Clear SSL network buffer"::formatted); + cleanNetworkBuffer(receivedBuffer); return total; } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java index dc197d5f..120c9baa 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java @@ -85,7 +85,7 @@ protected boolean tryToSendNextPacketImpl() { return super.tryToSendNextPacketImpl(); } - ByteBuffer dataToSend = doHandshake(SslWritableNetworkPacket.getInstance()); + ByteBuffer dataToSend = doHandshake(status); if (dataToSend != null) { return writeBuffer(dataToSend, null); } @@ -95,49 +95,38 @@ protected boolean tryToSendNextPacketImpl() { @Override protected ByteBuffer serialize(WritableNetworkPacket packet) { - HandshakeStatus status = sslEngine.getHandshakeStatus(); - if (SslUtils.isReadyToCrypt(status)) { - if (packet instanceof SslWritableNetworkPacket) { - return EMPTY_BUFFER; - } - - ByteBuffer serialized = super.serialize(packet); + if (packet instanceof SslWritableNetworkPacket) { + return EMPTY_BUFFER; + } - log.debug(remoteAddress(), serialized, (address, buff) -> - "[%s] Try to encrypt data:\n%s".formatted(address, hexDump(buff))); + ByteBuffer serialized = super.serialize(packet); + log.debug(remoteAddress(), serialized, (address, buff) -> + "[%s] Try to encrypt data:\n%s".formatted(address, hexDump(buff))); - ByteBuffer bufferToSend = sslNetworkBuffer(); - SSLEngineResult result = tryEncrypt(serialized, bufferToSend); + ByteBuffer bufferToSend = sslNetworkBuffer(); + SSLEngineResult result = tryEncrypt(serialized, bufferToSend); - if (result.getStatus() == SSLEngineResult.Status.OK && serialized.hasRemaining()) { - int tempBufferSize = (int) ((bufferToSend.limit() + serialized.remaining()) * 1.2); - ByteBuffer tempBuffer = bufferAllocator.takeBuffer(tempBufferSize); - tempBuffer.put(bufferToSend.flip()); - while (serialized.hasRemaining()) { - result = tryEncrypt(serialized, bufferToSend); - if (result.getStatus() != SSLEngineResult.Status.OK) { - break; - } - tempBuffer.put(bufferToSend.flip()); + if (result.getStatus() == SSLEngineResult.Status.OK && serialized.hasRemaining()) { + int tempBufferSize = (int) ((bufferToSend.limit() + serialized.remaining()) * 1.2); + ByteBuffer tempBuffer = bufferAllocator.takeBuffer(tempBufferSize); + tempBuffer.put(bufferToSend.flip()); + while (serialized.hasRemaining()) { + result = tryEncrypt(serialized, bufferToSend); + if (result.getStatus() != SSLEngineResult.Status.OK) { + break; } - bufferToSend = tempBuffer; - this.sslTempBuffer = tempBuffer; + tempBuffer.put(bufferToSend.flip()); } - - return switch (result.getStatus()) { - case BUFFER_UNDERFLOW -> increaseAndTryAgain(packet); - case BUFFER_OVERFLOW -> throw new IllegalStateException("Unexpected ssl engine result"); - case OK -> bufferToSend.flip(); - case CLOSED -> closeAndReturn(); - }; - } - - ByteBuffer dataToSend = doHandshake(packet); - if (dataToSend != null) { - return dataToSend; + bufferToSend = tempBuffer; + this.sslTempBuffer = tempBuffer; } - throw new IllegalStateException(); + return switch (result.getStatus()) { + case BUFFER_UNDERFLOW -> increaseAndTryAgain(packet); + case BUFFER_OVERFLOW -> throw new IllegalStateException("Unexpected ssl engine result"); + case OK -> bufferToSend.flip(); + case CLOSED -> closeAndReturn(); + }; } protected ByteBuffer closeAndReturn() { @@ -161,17 +150,12 @@ protected SSLEngineResult tryEncrypt(ByteBuffer source, ByteBuffer destination) } @Nullable - protected ByteBuffer doHandshake(WritableNetworkPacket packet) { - if (!(packet instanceof SslWritableNetworkPacket)) { - log.debug(remoteAddress(), packet, "[%s] Return packet:[%s] to queue as first"::formatted); - queueAtFirst.accept(packet); - } - - HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); + protected ByteBuffer doHandshake(HandshakeStatus handshakeStatus) { while (SslUtils.needToProcess(handshakeStatus)) { - SSLEngineResult result; + log.debug(remoteAddress(), handshakeStatus, "[%s] Do handshake with status:[%s] "::formatted); switch (handshakeStatus) { case NEED_WRAP: { + SSLEngineResult result; try { result = sslEngine.wrap(EMPTY_BUFFERS, sslNetworkBuffer.clear()); handshakeStatus = result.getHandshakeStatus(); @@ -182,16 +166,11 @@ protected ByteBuffer doHandshake(WritableNetworkPacket packet) { handshakeStatus = sslEngine.getHandshakeStatus(); break; } - switch (result.getStatus()) { case OK: - sslNetworkBuffer.flip(); -/* if (handshakeStatus == HandshakeStatus.NEED_WRAP) { - log.debug("Send command to wrap data again"); - queueAtFirst.accept(SslWritableNetworkPacket.getInstance()); - }*/ - log.debug(sslNetworkBuffer, result, (buf, res) -> "Send wrapped data:\n" + hexDump(buf, res)); - return sslNetworkBuffer; + log.debug(remoteAddress(), sslNetworkBuffer, result, + (address, buf, res) -> "[%s] Send wrapped data:\n%s".formatted(address, hexDump(buf, res))); + return sslNetworkBuffer.flip(); case BUFFER_OVERFLOW: { log.debug(remoteAddress(), "[%s] Increase network buffer"::formatted); increaseNetworkBuffer(); From 115a6805914b8abe6cfff5aea2b0ac15d0f62835 Mon Sep 17 00:00:00 2001 From: javasabr Date: Mon, 6 Oct 2025 20:24:10 +0200 Subject: [PATCH 14/15] finish updating ssl network implementation --- .../network/StringSslNetworkLoadTest.java | 6 +- .../impl/AbstractSslNetworkPacketReader.java | 120 ++++++++++-------- .../impl/AbstractSslNetworkPacketWriter.java | 71 ++++++----- .../packet/impl/SslWrapRequestPacket.java | 19 +++ .../packet/impl/SslWritableNetworkPacket.java | 20 --- .../packet/impl/StringReadablePacket.java | 6 - .../impl/StringWritableNetworkPacket.java | 15 +-- .../rlib/network/util/NetworkUtils.java | 31 ++--- .../rlib/network/StringSslNetworkTest.java | 11 +- 9 files changed, 145 insertions(+), 154 deletions(-) create mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWrapRequestPacket.java delete mode 100644 rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWritableNetworkPacket.java diff --git a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java index 665b54a9..1338f13d 100644 --- a/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java +++ b/rlib-network/src/loadTest/java/javasabr/rlib/network/StringSslNetworkLoadTest.java @@ -198,7 +198,7 @@ private static void initReceivedMessagesTracker( .getThenReset(); log.info(received, "Server receiving [%s] messages/sec"::formatted); if (received == 0) { - // finalWaiter.countDown(); + finalWaiter.countDown(); } }, 1, 1, TimeUnit.SECONDS); scheduledExecutor.scheduleAtFixedRate(() -> { @@ -216,8 +216,6 @@ private static void initReceivedMessagesTracker( } private static StringWritableNetworkPacket newMessage(int minMessageLength, int maxMessageLength) { - String generate = StringUtils.generate(minMessageLength, maxMessageLength); - return new StringWritableNetworkPacket("a".repeat(generate.length())); - //return new StringWritableNetworkPacket(StringUtils.generate(minMessageLength, maxMessageLength)); + return new StringWritableNetworkPacket(StringUtils.generate(minMessageLength, maxMessageLength)); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java index b1acd19c..fdaeb2db 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketReader.java @@ -91,26 +91,11 @@ protected int readPackets(ByteBuffer readingBuffer) { } } - protected ByteBuffer moveDataToNetworkBuffer(ByteBuffer readingBuffer) { - log.debug(remoteAddress(), readingBuffer, - (address, buf) -> "[%s] Append new part of received data:\n%s".formatted(address, hexDump(buf))); - ByteBuffer sslNetworkBuffer = sslNetworkBuffer(); - int availableSpace = sslNetworkBuffer.capacity() - sslNetworkBuffer.limit(); - if (availableSpace >= readingBuffer.limit()) { - BufferUtils.appendAndClear(sslNetworkBuffer, readingBuffer); - } else { - sslNetworkBuffer = increaseNetworkBuffer(readingBuffer.limit()); - BufferUtils.appendAndClear(sslNetworkBuffer, readingBuffer); - } - log.debug(remoteAddress(), sslNetworkBuffer, - (address, buf) -> "[%s] Result pending received network data:\n%s".formatted(address, hexDump(buf))); - return sslNetworkBuffer; - } - protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { HandshakeStatus handshakeStatus = sslEngine.getHandshakeStatus(); + String remoteAddress = remoteAddress(); while (SslUtils.needToProcess(handshakeStatus)) { - log.debug(remoteAddress(), handshakeStatus, "[%s] Do handshake with status:[%s] "::formatted); + log.debug(remoteAddress, handshakeStatus, "[%s] Do handshake with status:[%s] "::formatted); switch (handshakeStatus) { case NEED_UNWRAP: { SSLEngineResult result; @@ -128,15 +113,14 @@ protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { handshakeStatus = sslEngine.getHandshakeStatus(); break; } else if (!networkBuffer.hasRemaining()) { - cleanNetworkBuffer(networkBuffer); + NetworkUtils.cleanNetworkBuffer(networkBuffer); return SKIP_READ_PACKETS; } try { - log.debug(remoteAddress(), networkBuffer, - (address, buff) -> "[%s] Try to unwrap data:\n%s".formatted(address, hexDump(buff))); + logDataBeforeUnwrap(remoteAddress, networkBuffer); result = sslEngine.unwrap(networkBuffer, EMPTY_BUFFERS); handshakeStatus = result.getHandshakeStatus(); - log.debug(remoteAddress(), handshakeStatus, "[%s] Handshake status:[%s] after unwrapping"::formatted); + log.debug(remoteAddress, handshakeStatus, "[%s] Handshake status:[%s] after unwrapping"::formatted); } catch (SSLException sslException) { log.error("A problem was encountered while processing the data that caused the " + "SSLEngine to abort. Will try to properly close connection..."); @@ -149,15 +133,11 @@ protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { break; } case BUFFER_OVERFLOW: { - throw new IllegalStateException("Unexpected ssl engine result"); + throw new IllegalStateException("Unexpected SSL Engine result:" + result.getStatus()); } case BUFFER_UNDERFLOW: { - log.debug(remoteAddress(), "[%s] Wait for more received data..."::formatted); - if (networkBuffer.position() > 0) { - networkBuffer - .compact() - .limit(networkBuffer.position()); - } + log.debug(remoteAddress, "[%s] Wait for more received data..."::formatted); + NetworkUtils.compactNetworkBufferIfNeed(networkBuffer); return SKIP_READ_PACKETS; } case CLOSED: { @@ -170,28 +150,28 @@ protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { } } default: { - throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + throw new IllegalStateException("Invalid SSL Engine result:" + result.getStatus()); } } break; } case NEED_WRAP: { - log.debug(remoteAddress(), "[%s] Send command to wrap data"::formatted); - packetWriter.accept(SslWritableNetworkPacket.getInstance()); - cleanNetworkBuffer(networkBuffer); + log.debug(remoteAddress, "[%s] Send command to wrap data"::formatted); + packetWriter.accept(SslWrapRequestPacket.getInstance()); + NetworkUtils.cleanNetworkBuffer(networkBuffer); return SKIP_READ_PACKETS; } case NEED_TASK: { handshakeStatus = SslUtils.executeSslTasks(sslEngine); - log.debug(remoteAddress(), handshakeStatus, "[%s] Handshake status:[%s] after engine tasks"::formatted); + log.debug(remoteAddress, handshakeStatus, "[%s] Handshake status:[%s] after engine tasks"::formatted); if (handshakeStatus == HandshakeStatus.NEED_UNWRAP && !networkBuffer.hasRemaining()) { - cleanNetworkBuffer(networkBuffer); + NetworkUtils.cleanNetworkBuffer(networkBuffer); return SKIP_READ_PACKETS; } break; } default: { - throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); + throw new IllegalStateException("Invalid SSL status:" + handshakeStatus); } } } @@ -199,9 +179,9 @@ protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { if (!networkBuffer.hasRemaining()) { // if buffer is empty and status is FINISHED then we can notify writer if (handshakeStatus == HandshakeStatus.FINISHED) { - packetWriter.accept(SslWritableNetworkPacket.getInstance()); + packetWriter.accept(SslWrapRequestPacket.getInstance()); } - cleanNetworkBuffer(networkBuffer); + NetworkUtils.cleanNetworkBuffer(networkBuffer); return SKIP_READ_PACKETS; } @@ -209,12 +189,13 @@ protected int doHandshake(ByteBuffer networkBuffer, int receivedBytes) { } protected int decryptAndRead(ByteBuffer receivedBuffer) { + String remoteAddress = remoteAddress(); int total = 0; while (receivedBuffer.hasRemaining()) { + ByteBuffer sslDataBuffer = sslDataBuffer(); SSLEngineResult result; try { - log.debug(remoteAddress(), receivedBuffer, - (address, buf) -> "[%s] Try to decrypt data:\n%s".formatted(address, hexDump(buf))); + logDataBeforeDecrypt(remoteAddress, receivedBuffer); result = sslEngine.unwrap(receivedBuffer, sslDataBuffer.clear()); } catch (SSLException e) { throw new IllegalStateException(e); @@ -222,23 +203,18 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { switch (result.getStatus()) { case OK: { sslDataBuffer.flip(); - log.debug(remoteAddress(), sslDataBuffer, - (address, buf) -> "[%s] Decrypted data:\n%s".formatted(address, hexDump(buf))); + logDataAfterDecrypt(remoteAddress, sslDataBuffer); total += readPackets(sslDataBuffer, sslDataPendingBuffer); break; } case BUFFER_OVERFLOW: { - log.debug(remoteAddress(), "Increase SSL data buffer and try again..."::formatted); + log.debug(remoteAddress, "[%s] Increase SSL data buffer and try again..."::formatted); increaseDataBuffer(); return decryptAndRead(receivedBuffer); } case BUFFER_UNDERFLOW: { - log.debug(remoteAddress(), "[%s] Wait for more received data..."::formatted); - if (receivedBuffer.position() > 0) { - receivedBuffer - .compact() - .limit(receivedBuffer.position()); - } + log.debug(remoteAddress, "[%s] Wait for more received data..."::formatted); + NetworkUtils.compactNetworkBufferIfNeed(receivedBuffer); return SKIP_READ_PACKETS; } case CLOSED: { @@ -246,16 +222,33 @@ protected int decryptAndRead(ByteBuffer receivedBuffer) { return SKIP_READ_PACKETS; } default: { - throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + throw new IllegalStateException("Invalid SSL status:" + result.getStatus()); } } } - log.debug(remoteAddress(), "[%s] Clear SSL network buffer"::formatted); - cleanNetworkBuffer(receivedBuffer); + log.debug(remoteAddress, "[%s] Clear SSL network buffer"::formatted); + NetworkUtils.cleanNetworkBuffer(receivedBuffer); return total; } + protected ByteBuffer moveDataToNetworkBuffer(ByteBuffer readingBuffer) { + String remoteAddress = remoteAddress(); + logAcceptedNewDataPart(remoteAddress, readingBuffer); + + ByteBuffer sslNetworkBuffer = sslNetworkBuffer(); + int availableSpace = sslNetworkBuffer.capacity() - sslNetworkBuffer.limit(); + if (availableSpace >= readingBuffer.limit()) { + BufferUtils.appendAndClear(sslNetworkBuffer, readingBuffer); + } else { + sslNetworkBuffer = increaseNetworkBuffer(readingBuffer.limit()); + BufferUtils.appendAndClear(sslNetworkBuffer, readingBuffer); + } + + logPendingNetworkData(remoteAddress, sslNetworkBuffer); + return sslNetworkBuffer; + } + protected synchronized ByteBuffer increaseNetworkBuffer(int extra) { ByteBuffer current = sslNetworkBuffer(); int newSize = (int) Math.max(current.capacity() * 1.3, current.capacity() + extra); @@ -287,7 +280,28 @@ public void close() { super.close(); } - protected static void cleanNetworkBuffer(ByteBuffer networkBuffer) { - networkBuffer.clear().limit(0); + private static void logDataBeforeUnwrap(String remoteAddress, ByteBuffer networkBuffer) { + log.debug(remoteAddress, networkBuffer, + (address, buff) -> "[%s] Try to unwrap data:\n%s".formatted(address, hexDump(buff))); + } + + private static void logDataBeforeDecrypt(String remoteAddress, ByteBuffer receivedBuffer) { + log.debug(remoteAddress, receivedBuffer, + (address, buf) -> "[%s] Try to decrypt data:\n%s".formatted(address, hexDump(buf))); + } + + private static void logDataAfterDecrypt(String remoteAddress, ByteBuffer sslDataBuffer) { + log.debug(remoteAddress, sslDataBuffer, + (address, buf) -> "[%s] Decrypted data:\n%s".formatted(address, hexDump(buf))); + } + + private static void logAcceptedNewDataPart(String remoteAddress, ByteBuffer readingBuffer) { + log.debug(remoteAddress, readingBuffer, + (address, buf) -> "[%s] Append new part of received data:\n%s".formatted(address, hexDump(buf))); + } + + private static void logPendingNetworkData(String remoteAddress, ByteBuffer sslNetworkBuffer) { + log.debug(remoteAddress, sslNetworkBuffer, + (address, buf) -> "[%s] Result pending received network data:\n%s".formatted(address, hexDump(buf))); } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java index 120c9baa..bbd649e3 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/AbstractSslNetworkPacketWriter.java @@ -95,21 +95,25 @@ protected boolean tryToSendNextPacketImpl() { @Override protected ByteBuffer serialize(WritableNetworkPacket packet) { - if (packet instanceof SslWritableNetworkPacket) { + if (packet instanceof SslWrapRequestPacket) { return EMPTY_BUFFER; } + String remoteAddress = remoteAddress(); ByteBuffer serialized = super.serialize(packet); - log.debug(remoteAddress(), serialized, (address, buff) -> - "[%s] Try to encrypt data:\n%s".formatted(address, hexDump(buff))); + logDataBeforeEncrypt(remoteAddress, serialized); ByteBuffer bufferToSend = sslNetworkBuffer(); SSLEngineResult result = tryEncrypt(serialized, bufferToSend); if (result.getStatus() == SSLEngineResult.Status.OK && serialized.hasRemaining()) { + log.debug(remoteAddress, serialized.remaining(), + "[%s] Has remaining [%s] bytes after encrypting, will create temp big buffer"::formatted); + int tempBufferSize = (int) ((bufferToSend.limit() + serialized.remaining()) * 1.2); ByteBuffer tempBuffer = bufferAllocator.takeBuffer(tempBufferSize); tempBuffer.put(bufferToSend.flip()); + while (serialized.hasRemaining()) { result = tryEncrypt(serialized, bufferToSend); if (result.getStatus() != SSLEngineResult.Status.OK) { @@ -117,14 +121,19 @@ protected ByteBuffer serialize(WritableNetworkPacket packet) { } tempBuffer.put(bufferToSend.flip()); } + bufferToSend = tempBuffer; this.sslTempBuffer = tempBuffer; } return switch (result.getStatus()) { - case BUFFER_UNDERFLOW -> increaseAndTryAgain(packet); - case BUFFER_OVERFLOW -> throw new IllegalStateException("Unexpected ssl engine result"); - case OK -> bufferToSend.flip(); + case BUFFER_UNDERFLOW, BUFFER_OVERFLOW -> + throw new IllegalStateException("Unexpected ssl engine result"); + case OK -> { + bufferToSend.flip(); + logEncryptedData(remoteAddress, bufferToSend); + yield bufferToSend; + } case CLOSED -> closeAndReturn(); }; } @@ -134,12 +143,6 @@ protected ByteBuffer closeAndReturn() { return EMPTY_BUFFER; } - protected ByteBuffer increaseAndTryAgain(WritableNetworkPacket packet) { - log.debug(remoteAddress(), "[%s] Increase network buffer and try again..."::formatted); - increaseNetworkBuffer(); - return serialize(packet); - } - protected SSLEngineResult tryEncrypt(ByteBuffer source, ByteBuffer destination) { try { return sslEngine.wrap(source, destination.clear()); @@ -151,14 +154,15 @@ protected SSLEngineResult tryEncrypt(ByteBuffer source, ByteBuffer destination) @Nullable protected ByteBuffer doHandshake(HandshakeStatus handshakeStatus) { + String remoteAddress = remoteAddress(); while (SslUtils.needToProcess(handshakeStatus)) { - log.debug(remoteAddress(), handshakeStatus, "[%s] Do handshake with status:[%s] "::formatted); + log.debug(remoteAddress, handshakeStatus, "[%s] Do handshake with status:[%s] "::formatted); + ByteBuffer sslNetworkBuffer = sslNetworkBuffer(); switch (handshakeStatus) { case NEED_WRAP: { SSLEngineResult result; try { result = sslEngine.wrap(EMPTY_BUFFERS, sslNetworkBuffer.clear()); - handshakeStatus = result.getHandshakeStatus(); } catch (SSLException sslException) { log.error("A problem was encountered while processing the data that caused the SSLEngine " + "to abort. Will try to properly close connection..."); @@ -168,16 +172,11 @@ protected ByteBuffer doHandshake(HandshakeStatus handshakeStatus) { } switch (result.getStatus()) { case OK: - log.debug(remoteAddress(), sslNetworkBuffer, result, - (address, buf, res) -> "[%s] Send wrapped data:\n%s".formatted(address, hexDump(buf, res))); - return sslNetworkBuffer.flip(); - case BUFFER_OVERFLOW: { - log.debug(remoteAddress(), "[%s] Increase network buffer"::formatted); - increaseNetworkBuffer(); - break; - } - case BUFFER_UNDERFLOW: { - throw new IllegalStateException("Unexpected ssl engine result"); + sslNetworkBuffer.flip(); + logWrappedData(remoteAddress, sslNetworkBuffer, result); + return sslNetworkBuffer; + case BUFFER_OVERFLOW, BUFFER_UNDERFLOW: { + throw new RuntimeException("Unexpected SSL result:" + result); } case CLOSED: { try { @@ -189,7 +188,7 @@ protected ByteBuffer doHandshake(HandshakeStatus handshakeStatus) { break; } default: { - throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); + throw new IllegalStateException("Invalid SSL result:" + result); } } break; @@ -202,7 +201,7 @@ protected ByteBuffer doHandshake(HandshakeStatus handshakeStatus) { break; } default: { - throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); + throw new IllegalStateException("Invalid SSL status:" + handshakeStatus); } } } @@ -220,15 +219,25 @@ protected void clearTempBuffers() { } } - protected synchronized void increaseNetworkBuffer() { - sslNetworkBuffer = NetworkUtils - .increasePacketBuffer(sslNetworkBuffer, bufferAllocator, sslEngine); - } - @Override public void close() { sslEngine.closeOutbound(); bufferAllocator.putBuffer(sslNetworkBuffer); super.close(); } + + private static void logDataBeforeEncrypt(String remoteAddress, ByteBuffer serialized) { + log.debug(remoteAddress, serialized, + (address, buff) -> "[%s] Try to encrypt data:\n%s".formatted(address, hexDump(buff))); + } + + private static void logEncryptedData(String remoteAddress, ByteBuffer bufferToSend) { + log.debug(remoteAddress, bufferToSend, + (address, buff) -> "[%s] Result encrypted data:\n%s".formatted(address, hexDump(buff))); + } + + private static void logWrappedData(String remoteAddress, ByteBuffer sslNetworkBuffer, SSLEngineResult result) { + log.debug(remoteAddress, sslNetworkBuffer, result, + (address, buf, res) -> "[%s] Send wrapped data:\n%s".formatted(address, hexDump(buf, res))); + } } diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWrapRequestPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWrapRequestPacket.java new file mode 100644 index 00000000..4d12d963 --- /dev/null +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWrapRequestPacket.java @@ -0,0 +1,19 @@ +package javasabr.rlib.network.packet.impl; + +import java.nio.ByteBuffer; +import javasabr.rlib.network.packet.MarkerNetworkPacket; + +public class SslWrapRequestPacket extends AbstractWritableNetworkPacket + implements MarkerNetworkPacket { + + private static final SslWrapRequestPacket INSTANCE = new SslWrapRequestPacket(); + + public static SslWrapRequestPacket getInstance() { + return INSTANCE; + } + + @Override + public boolean write(ByteBuffer buffer) { + return true; + } +} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWritableNetworkPacket.java deleted file mode 100644 index 418b95c0..00000000 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/SslWritableNetworkPacket.java +++ /dev/null @@ -1,20 +0,0 @@ -package javasabr.rlib.network.packet.impl; - -import java.nio.ByteBuffer; - -/** - * Packet marker. - */ -public class SslWritableNetworkPacket extends AbstractWritableNetworkPacket { - - private static final SslWritableNetworkPacket INSTANCE = new SslWritableNetworkPacket(); - - public static SslWritableNetworkPacket getInstance() { - return INSTANCE; - } - - @Override - public boolean write(ByteBuffer buffer) { - return true; - } -} diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java index ce25eac2..a896ef20 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringReadablePacket.java @@ -22,13 +22,7 @@ public class StringReadablePacket extends AbstractReadableNetworkPacket { @Override protected void readImpl(ByteBuffer buffer) { - readLong(buffer); - readLong(buffer); - readLong(buffer); this.data = readString(buffer, MAX_LENGTH); - readLong(buffer); - readLong(buffer); - readLong(buffer); } @Override diff --git a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java index 524685db..0c7a4542 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/packet/impl/StringWritableNetworkPacket.java @@ -1,35 +1,32 @@ package javasabr.rlib.network.packet.impl; import java.nio.ByteBuffer; +import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; /** * @author JavaSaBr */ @Getter -@Accessors(fluent = true, chain = false) @RequiredArgsConstructor +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class StringWritableNetworkPacket extends AbstractWritableNetworkPacket { - private final String data; + String data; @Override protected void writeImpl(ByteBuffer buffer) { super.writeImpl(buffer); - writeLong(buffer, 0); - writeLong(buffer, Long.MAX_VALUE); - writeLong(buffer, Long.MAX_VALUE); writeString(buffer, data); - writeLong(buffer, Long.MAX_VALUE); - writeLong(buffer, 0); - writeLong(buffer, 0); } @Override public int expectedLength() { - return 48 + 4 + data.length() * 2; + return 4 + data.length() * 2; } @Override diff --git a/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java b/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java index 01dd27c0..71e21c6c 100644 --- a/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java +++ b/rlib-network/src/main/java/javasabr/rlib/network/util/NetworkUtils.java @@ -15,7 +15,6 @@ import javasabr.rlib.network.BufferAllocator; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; @@ -279,22 +278,6 @@ public static int getAvailablePort(int port) { .orElse(-1); } - public static ByteBuffer increasePacketBuffer( - ByteBuffer current, - BufferAllocator allocator, - SSLEngine engine) { - - var newBuffer = allocator.takeBuffer(engine - .getSession() - .getPacketBufferSize()); - newBuffer.put(current); - - if (current.capacity() > 0) { - allocator.putBuffer(current); - } - - return newBuffer; - } public static ByteBuffer increaseBuffer(ByteBuffer current, BufferAllocator allocator, int newSize) { @@ -308,11 +291,13 @@ public static ByteBuffer increaseBuffer(ByteBuffer current, BufferAllocator allo return newBuffer; } - public static ByteBuffer enlargeApplicationBuffer( - BufferAllocator allocator, - SSLEngine engine) { - return allocator.takeBuffer(engine - .getSession() - .getApplicationBufferSize()); + public static void cleanNetworkBuffer(ByteBuffer networkBuffer) { + networkBuffer.clear().limit(0); + } + + public static void compactNetworkBufferIfNeed(ByteBuffer networkBuffer) { + if (networkBuffer.position() > 0) { + networkBuffer.compact().limit(networkBuffer.position()); + } } } diff --git a/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java b/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java index ebbed521..da87ee0e 100644 --- a/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java +++ b/rlib-network/src/test/java/javasabr/rlib/network/StringSslNetworkTest.java @@ -213,7 +213,7 @@ void clientSslNetworkTest() { @SneakyThrows void echoNetworkTest() { //System.setProperty("javax.net.debug", "all"); - LoggerManager.enable(StringSslNetworkTest.class, LoggerLevel.INFO); + //LoggerManager.enable(StringSslNetworkTest.class, LoggerLevel.INFO); InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); @@ -272,11 +272,6 @@ void echoNetworkTest() { serverNetwork.shutdown(); clientNetwork.shutdown(); - - ThreadUtils.sleep(30000); - //LoggerManager.disable(AbstractSSLPacketWriter.class, LoggerLevel.DEBUG); - //LoggerManager.disable(AbstractSSLPacketReader.class, LoggerLevel.DEBUG); - //LoggerManager.disable(AbstractPacketWriter.class, LoggerLevel.DEBUG); } @Test @@ -285,8 +280,8 @@ void shouldReceiveManyPacketsFromSmallToBigSize() { //System.setProperty("javax.net.debug", "all"); //LoggerManager.enable(AbstractPacketReader.class, LoggerLevel.DEBUG); //LoggerManager.enable(AbstractPacketWriter.class, LoggerLevel.DEBUG); - LoggerManager.enable(AbstractSslNetworkPacketWriter.class, LoggerLevel.DEBUG); - LoggerManager.enable(AbstractSslNetworkPacketReader.class, LoggerLevel.DEBUG); + //LoggerManager.enable(AbstractSslNetworkPacketWriter.class, LoggerLevel.DEBUG); + //LoggerManager.enable(AbstractSslNetworkPacketReader.class, LoggerLevel.DEBUG); InputStream keystoreFile = StringSslNetworkTest.class.getResourceAsStream("/ssl/rlib_test_cert.p12"); SSLContext serverSSLContext = NetworkUtils.createSslContext(keystoreFile, "test"); From dbcb6638184d74b5dc876c402f66baa78e5b1c74 Mon Sep 17 00:00:00 2001 From: javasabr Date: Mon, 6 Oct 2025 20:31:16 +0200 Subject: [PATCH 15/15] fix test aggregation --- test-coverage/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/test-coverage/build.gradle b/test-coverage/build.gradle index 91ce11b2..dfeca12a 100644 --- a/test-coverage/build.gradle +++ b/test-coverage/build.gradle @@ -1,4 +1,5 @@ plugins { + id("configure-java") id("jacoco-report-aggregation") }