From 01ebb11708dd505c35abe6e6a6db7714ba3ddeac Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Tue, 13 Sep 2022 12:05:02 +0530
Subject: [PATCH 01/25] Update logic for finding optimal keepalive (#41)
* Reset state when optimal keepalive is failed
* Update keepalive handling logic on failure
* Reset state on network change without connected check
* Fix unit tests
---
.../keepalive/AdaptiveKeepAliveStateHandler.kt | 8 ++++----
.../gojek/keepalive/OptimalKeepAliveCalculator.kt | 9 ++++-----
.../keepalive/OptimalKeepAliveCalculatorTest.kt | 15 ++-------------
3 files changed, 10 insertions(+), 22 deletions(-)
diff --git a/adaptive-keep-alive/src/main/java/com/gojek/keepalive/AdaptiveKeepAliveStateHandler.kt b/adaptive-keep-alive/src/main/java/com/gojek/keepalive/AdaptiveKeepAliveStateHandler.kt
index 20f5467c..60377261 100644
--- a/adaptive-keep-alive/src/main/java/com/gojek/keepalive/AdaptiveKeepAliveStateHandler.kt
+++ b/adaptive-keep-alive/src/main/java/com/gojek/keepalive/AdaptiveKeepAliveStateHandler.kt
@@ -98,7 +98,7 @@ internal class AdaptiveKeepAliveStateHandler(
)
} else {
val currentUpperBound = keepAlive.keepAliveMinutes - 1
- if (state.lastSuccessfulKA == currentUpperBound) {
+ if (state.lastSuccessfulKA >= currentUpperBound) {
state = state.copy(
currentUpperBound = currentUpperBound,
isOptimalKeepAlive = true,
@@ -191,8 +191,7 @@ internal class AdaptiveKeepAliveStateHandler(
keepAlive.keepAliveMinutes == state.currentKA
}
- @VisibleForTesting
- internal fun resetState() {
+ fun resetState() {
state = state.copy(
lastSuccessfulKA = state.lowerBound - state.step,
isOptimalKeepAlive = false,
@@ -201,7 +200,8 @@ internal class AdaptiveKeepAliveStateHandler(
currentKA = -1,
currentKAFailureCount = 0,
probeCount = 0,
- convergenceTime = 0
+ convergenceTime = 0,
+ optimalKAFailureCount = 0
)
}
diff --git a/adaptive-keep-alive/src/main/java/com/gojek/keepalive/OptimalKeepAliveCalculator.kt b/adaptive-keep-alive/src/main/java/com/gojek/keepalive/OptimalKeepAliveCalculator.kt
index f61b6022..8f879658 100644
--- a/adaptive-keep-alive/src/main/java/com/gojek/keepalive/OptimalKeepAliveCalculator.kt
+++ b/adaptive-keep-alive/src/main/java/com/gojek/keepalive/OptimalKeepAliveCalculator.kt
@@ -20,11 +20,9 @@ internal class OptimalKeepAliveCalculator(
object : NetworkStateListener {
override fun onStateChanged(activeNetworkState: NetworkState) {
synchronized(this) {
- if (activeNetworkState.isConnected) {
- val networkType = networkUtils.getNetworkType(activeNetworkState.netInfo)
- val networkName = networkUtils.getNetworkName(activeNetworkState.netInfo)
- onNetworkStateChanged(networkType, networkName)
- }
+ val networkType = networkUtils.getNetworkType(activeNetworkState.netInfo)
+ val networkName = networkUtils.getNetworkName(activeNetworkState.netInfo)
+ onNetworkStateChanged(networkType, networkName)
}
}
}
@@ -108,6 +106,7 @@ internal class OptimalKeepAliveCalculator(
stateHandler.updateOptimalKeepAliveFailureState()
if (stateHandler.isOptimalKeepAliveFailureLimitExceeded()) {
stateHandler.removeStateFromPersistence()
+ stateHandler.resetState()
}
}
}
diff --git a/adaptive-keep-alive/src/test/java/com/gojek/keepalive/OptimalKeepAliveCalculatorTest.kt b/adaptive-keep-alive/src/test/java/com/gojek/keepalive/OptimalKeepAliveCalculatorTest.kt
index f5ca76d0..9b729073 100644
--- a/adaptive-keep-alive/src/test/java/com/gojek/keepalive/OptimalKeepAliveCalculatorTest.kt
+++ b/adaptive-keep-alive/src/test/java/com/gojek/keepalive/OptimalKeepAliveCalculatorTest.kt
@@ -39,10 +39,9 @@ class OptimalKeepAliveCalculatorTest {
}
@Test
- fun `test onStateChanged should notify state handler when network is connected`() {
+ fun `test onStateChanged should notify state handler`() {
val networkState = mock()
val netInfo = mock()
- whenever(networkState.isConnected).thenReturn(true)
whenever(networkState.netInfo).thenReturn(netInfo)
val networkType = 1
val networkName = "test-network"
@@ -52,23 +51,12 @@ class OptimalKeepAliveCalculatorTest {
optimalKeepAliveCalculator.networkStateListener.onStateChanged(networkState)
verify(stateHandler).onNetworkChanged(networkType, networkName)
- verify(networkState).isConnected
verify(networkState, times(2)).netInfo
verify(networkUtils).getNetworkType(netInfo)
verify(networkUtils).getNetworkName(netInfo)
verifyNoMoreInteractions(networkState)
}
- @Test
- fun `test onStateChanged should not notify state handler when network is not connected`() {
- val networkState = mock()
- whenever(networkState.isConnected).thenReturn(false)
-
- optimalKeepAliveCalculator.networkStateListener.onStateChanged(networkState)
-
- verify(networkState).isConnected
- }
-
@Test
fun `test getUnderTrialKeepAlive when optimal keep alive is already found`() {
val optimalKeepAlive = mock()
@@ -271,6 +259,7 @@ class OptimalKeepAliveCalculatorTest {
verify(stateHandler).updateOptimalKeepAliveFailureState()
verify(stateHandler).isOptimalKeepAliveFailureLimitExceeded()
verify(stateHandler).removeStateFromPersistence()
+ verify(stateHandler).resetState()
}
@Test
From 13b166b9d97a8523dacbc59674533b824425f6a0 Mon Sep 17 00:00:00 2001
From: Anubhav Gupta
Date: Wed, 28 Sep 2022 11:27:32 +0530
Subject: [PATCH 02/25] Improved TLS handling and add support for ALPN (#43)
* Improved tls handling and add support for alpn
* removed socket factory from connection config
* applied spotless
* added expeirmental config for new ssl flow
* dump public api
* corrected sample app
* fixed test failures
* removed redundant code and required checks
* fixed review comments
* converted paho to java module
* updated docs
* add back required checks
* fixed broker docs link
Co-authored-by: Anubhav Gupta
---
adaptive-keep-alive/build.gradle.kts | 1 +
.../com/gojek/courier/app/ui/MainActivity.kt | 23 +-
build.gradle.kts | 6 +-
buildSrc/src/main/kotlin/deps.kt | 1 +
courier-auth-http/build.gradle.kts | 1 +
docs/docs/ConnectionSetup.md | 28 +-
docs/docs/ExperimentConfigs.md | 4 +-
docs/docs/MqttConfiguration.md | 2 -
docs/docs/NonStandardOptions.md | 20 +-
mqtt-client/api/mqtt-client.api | 89 ++-
mqtt-client/build.gradle.kts | 1 +
.../mqtt/client/config/ExperimentConfigs.kt | 3 +-
.../mqtt/client/config/MqttConfiguration.kt | 2 -
.../client/config/v3/MqttV3Configuration.kt | 3 -
.../mqtt/client/v3/impl/AndroidMqttClient.kt | 20 +-
.../gojek/mqtt/connection/MqttConnection.kt | 43 +-
.../connection/config/v3/ConnectionConfig.kt | 5 +-
.../java/com/gojek/mqtt/model/KeepAlive.kt | 6 +-
.../gojek/mqtt/model/MqttConnectOptions.kt | 224 +++++-
.../v3/impl/MqttExceptionHandlerImplTest.kt | 36 +-
network-tracker/build.gradle.kts | 1 +
paho/build.gradle.kts | 12 +-
paho/src/main/AndroidManifest.xml | 3 +
.../paho/client/mqttv3/ConnectionSpec.kt | 375 ++++++++++
.../client/mqttv3/IExperimentsConfig.java | 2 +
.../paho/client/mqttv3/MqttAsyncClient.java | 212 +++---
.../client/mqttv3/MqttConnectOptions.java | 44 ++
.../eclipse/paho/client/mqttv3/Protocol.kt | 5 +
.../client/mqttv3/SuppressSignatureCheck.kt | 12 +
.../org/eclipse/paho/client/mqttv3/Util.kt | 68 ++
.../mqttv3/internal/SSLNetworkModule.java | 9 +-
.../mqttv3/internal/SSLNetworkModuleV2.java | 122 ++++
.../internal/platform/Android10Platform.kt | 89 +++
.../internal/platform/AndroidPlatform.kt | 155 ++++
.../internal/platform/BouncyCastlePlatform.kt | 104 +++
.../internal/platform/ConscryptPlatform.kt | 140 ++++
.../platform/Jdk8WithJettyBootPlatform.kt | 166 +++++
.../mqttv3/internal/platform/Jdk9Platform.kt | 105 +++
.../internal/platform/OpenJSSEPlatform.kt | 103 +++
.../mqttv3/internal/platform/Platform.kt | 284 ++++++++
.../android/Android10SocketAdapter.kt | 83 +++
.../android/AndroidCertificateChainCleaner.kt | 71 ++
.../platform/android/AndroidSocketAdapter.kt | 131 ++++
.../android/BouncyCastleSocketAdapter.kt | 68 ++
.../android/ConscryptSocketAdapter.kt | 65 ++
.../platform/android/DeferredSocketAdapter.kt | 64 ++
.../platform/android/SocketAdapter.kt | 36 +
.../android/StandardAndroidSocketAdapter.kt | 74 ++
.../tls/BasicCertificateChainCleaner.kt | 139 ++++
.../internal/tls/BasicTrustRootIndex.kt | 55 ++
.../internal/tls/CertificateChainCleaner.kt | 49 ++
.../client/mqttv3/internal/tls/CipherSuite.kt | 665 ++++++++++++++++++
.../client/mqttv3/internal/tls/TlsVersion.kt | 52 ++
.../mqttv3/internal/tls/TrustRootIndex.kt | 23 +
.../ExtendedByteArrayOutputStream.java | 12 +
.../WebSocketSecureNetworkModuleV2.java | 132 ++++
.../org.mockito.plugins.MockMaker | 1 +
pingsender/timer-pingsender/build.gradle.kts | 1 +
.../build.gradle.kts | 2 +-
.../workmanager-pingsender/build.gradle.kts | 2 +-
60 files changed, 4020 insertions(+), 234 deletions(-)
create mode 100644 paho/src/main/AndroidManifest.xml
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/ConnectionSpec.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/Protocol.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/SuppressSignatureCheck.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/Util.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/SSLNetworkModuleV2.java
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Android10Platform.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/AndroidPlatform.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/BouncyCastlePlatform.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/ConscryptPlatform.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Jdk8WithJettyBootPlatform.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Jdk9Platform.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/OpenJSSEPlatform.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Platform.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/Android10SocketAdapter.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidCertificateChainCleaner.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/BouncyCastleSocketAdapter.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/ConscryptSocketAdapter.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/DeferredSocketAdapter.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/SocketAdapter.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/StandardAndroidSocketAdapter.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/BasicCertificateChainCleaner.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/BasicTrustRootIndex.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/CertificateChainCleaner.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/CipherSuite.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/TlsVersion.kt
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/TrustRootIndex.kt
create mode 100755 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/websocket/WebSocketSecureNetworkModuleV2.java
create mode 100644 paho/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
diff --git a/adaptive-keep-alive/build.gradle.kts b/adaptive-keep-alive/build.gradle.kts
index 7039018a..d55df42a 100644
--- a/adaptive-keep-alive/build.gradle.kts
+++ b/adaptive-keep-alive/build.gradle.kts
@@ -46,6 +46,7 @@ dependencies {
implementation(project(":mqtt-pingsender"))
implementation(project(":network-tracker"))
+ testImplementation(deps.android.test.mockitoCore)
testImplementation(deps.android.test.kotlinTestJunit)
}
diff --git a/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt b/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt
index a5c89f6e..83a821c5 100644
--- a/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt
+++ b/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt
@@ -92,23 +92,20 @@ class MainActivity : AppCompatActivity() {
}
private fun connectMqtt(clientId: String, username: String, password: String, ip: String, port: Int) {
- val connectOptions = MqttConnectOptions(
- serverUris = listOf(ServerUri(ip, port, if (port == 443) "ssl" else "tcp")),
- clientId = clientId,
- username = username,
- keepAlive = KeepAlive(
- timeSeconds = 30
- ),
- isCleanSession = false,
- password = password
- )
+ val connectOptions = MqttConnectOptions.Builder()
+ .serverUris(listOf(ServerUri(ip, port, if (port == 443) "ssl" else "tcp")))
+ .clientId(clientId)
+ .userName(username)
+ .password(password)
+ .cleanSession(false)
+ .keepAlive(KeepAlive(timeSeconds = 30))
+ .build()
mqttClient.connect(connectOptions)
}
private fun initialiseCourier() {
val mqttConfig = MqttV3Configuration(
- socketFactory = null,
logger = getLogger(),
eventHandler = eventHandler,
authenticator = object : Authenticator {
@@ -116,7 +113,9 @@ class MainActivity : AppCompatActivity() {
connectOptions: MqttConnectOptions,
forceRefresh: Boolean
): MqttConnectOptions {
- return connectOptions.copy(password = password.text.toString())
+ return connectOptions.newBuilder()
+ .password(password.text.toString())
+ .build()
}
},
mqttInterceptorList = listOf(MqttChuckInterceptor(this, MqttChuckConfig(retentionPeriod = Period.ONE_HOUR))),
diff --git a/build.gradle.kts b/build.gradle.kts
index a3c80aa8..9119f06d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -41,12 +41,12 @@ allprojects {
subprojects {
tasks.withType().configureEach {
kotlinOptions {
- jvmTarget = "1.8"
+ jvmTarget = "11"
}
}
tasks.withType().configureEach {
- sourceCompatibility = JavaVersion.VERSION_1_8.toString()
- targetCompatibility = JavaVersion.VERSION_1_8.toString()
+ sourceCompatibility = JavaVersion.VERSION_11.toString()
+ targetCompatibility = JavaVersion.VERSION_11.toString()
}
}
diff --git a/buildSrc/src/main/kotlin/deps.kt b/buildSrc/src/main/kotlin/deps.kt
index 388f820e..fa26f2b9 100644
--- a/buildSrc/src/main/kotlin/deps.kt
+++ b/buildSrc/src/main/kotlin/deps.kt
@@ -59,6 +59,7 @@ object deps {
const val runner = "androidx.test:runner:1.2.0"
const val roboelectric = "org.robolectric:robolectric:4.2"
const val mockito = "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
+ const val mockitoCore = "org.mockito:mockito-core:4.4.0"
const val junitExt = "androidx.test.ext:junit:1.1.1"
const val kotlinTestJunit = "org.jetbrains.kotlin:kotlin-test-junit:${versions.kotlin}"
}
diff --git a/courier-auth-http/build.gradle.kts b/courier-auth-http/build.gradle.kts
index 974206fd..739c986d 100644
--- a/courier-auth-http/build.gradle.kts
+++ b/courier-auth-http/build.gradle.kts
@@ -30,6 +30,7 @@ dependencies {
implementation(deps.square.retrofit)
+ testImplementation(deps.android.test.mockitoCore)
testImplementation(deps.android.test.kotlinTestJunit)
}
diff --git a/docs/docs/ConnectionSetup.md b/docs/docs/ConnectionSetup.md
index 04bedde3..4c64e8ef 100644
--- a/docs/docs/ConnectionSetup.md
+++ b/docs/docs/ConnectionSetup.md
@@ -14,16 +14,16 @@ val mqttClient = MqttClientFactory.create(
### Connect using MqttClient
~~~ kotlin
-val connectOptions = MqttConnectOptions(
- serverUris = listOf(ServerUri(SERVER_URI, SERVER_PORT)),
- clientId = clientId,
- username = username,
- keepAlive = KeepAlive(
- timeSeconds = keepAliveSeconds
- ),
- isCleanSession = cleanSessionFlag,
- password = password
-)
+val alpnProtocol = "mqtt"
+val connectOptions = MqttConnectOptions.Builder()
+ .serverUris(listof(ServerUri(SERVER_URI, SERVER_PORT)))
+ .clientId(clientId)
+ .userName(username)
+ .password(password)
+ .keepAlive(KeepAlive(timeSeconds = keepAliveSeconds))
+ .cleanSession(cleanSessionFlag)
+ .alpnProtocols(listOf(Protocol(alpnProtocol)))
+ .build()
mqttClient.connect(connectOptions)
~~~
@@ -56,6 +56,14 @@ mqttClient.disconnect()
- **User properties** : Custom user properties appended to the CONNECT packet.
+- **Socket Factory** : Sets the socket factory used to create connections. If unset, the **SocketFactory.getDefault** socket factory will be used. Set [shouldUseNewSSLFlow](ExperimentConfigs) to true to enable this.
+
+- **SSL Socket Factory**: Sets the socket factory and trust manager used to secure MQTT connections. If unset, the system defaults will be used. Set [shouldUseNewSSLFlow](ExperimentConfigs) to true to enable this.
+
+- **Connection Spec**: Specifies configuration for the socket connection that MQTT traffic travels through. This includes the TLS version and cipher suites to use when negotiating a secure connection. Set [shouldUseNewSSLFlow](ExperimentConfigs) to true to enable this.
+
+- **ALPN Protocols**: Configure the alpn protocols used by this client to communicate with MQTT broker. Set [shouldUseNewSSLFlow](ExperimentConfigs) to true to enable this.
+
[1]: https://github.com/gojek/courier-android/blob/main/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttClient.kt
[2]: https://github.com/gojek/courier-android/blob/main/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
[3]: https://github.com/gojek/courier-android/blob/main/mqtt-client/src/main/java/com/gojek/mqtt/model/ServerUri.kt
diff --git a/docs/docs/ExperimentConfigs.md b/docs/docs/ExperimentConfigs.md
index 9fd5c0c8..a4f4f833 100644
--- a/docs/docs/ExperimentConfigs.md
+++ b/docs/docs/ExperimentConfigs.md
@@ -14,4 +14,6 @@ These are the experimentation configs used in Courier library. These are volatil
- **incomingMessagesTTLSecs** : When there is no listener attached for an incoming message, messages are persisted for this interval.
-- **incomingMessagesCleanupIntervalSecs** : Interval at which cleanup for incoming messages persistence is performed.
\ No newline at end of file
+- **incomingMessagesCleanupIntervalSecs** : Interval at which cleanup for incoming messages persistence is performed.
+
+- **shouldUseNewSSLFlow** : Set this true for enabling alpn protocol, custom ssl socket factory.
\ No newline at end of file
diff --git a/docs/docs/MqttConfiguration.md b/docs/docs/MqttConfiguration.md
index a93f3a56..55a438e4 100644
--- a/docs/docs/MqttConfiguration.md
+++ b/docs/docs/MqttConfiguration.md
@@ -22,8 +22,6 @@ As we have seen earlier, [MqttClient][1] requires an instance of [MqttV3Configur
- **Experimentation Configs** : These are the experiment configs used inside Courier library which are explained in detail [here](ExperimentConfigs).
-- **Socket Factory** : An instance of SocketFactory can be passed to control the socket creation for the underlying MQTT connection.
-
- **WakeLock Timeout** : When positive value of this timeout is passed, a wakelock is acquired while creating the MQTT connection. By default, it is 0.
[1]: https://github.com/gojek/courier-android/blob/main/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttClient.kt
diff --git a/docs/docs/NonStandardOptions.md b/docs/docs/NonStandardOptions.md
index 241e7445..641f6197 100644
--- a/docs/docs/NonStandardOptions.md
+++ b/docs/docs/NonStandardOptions.md
@@ -5,15 +5,17 @@
This option allows you to send user-properties in CONNECT packet for MQTT v3.1.1.
~~~ kotlin
-val connectOptions = MqttConnectOptions(
- serverUris = listOf(ServerUri(SERVER_URI, SERVER_PORT)),
- clientId = clientId,
- ...
- userPropertiesMap = mapOf(
- "key1" to "value1",
- "key2" to "value2"
- )
-)
+val connectOptions = MqttConnectOptions.Builder()
+ .serverUris(listOf(ServerUri(SERVER_URI, SERVER_PORT)))
+ .clientId(clientId)
+ ...
+ .userProperties(
+ userProperties = mapOf(
+ "key1" to "value1",
+ "key2" to "value2"
+ )
+ )
+ .build()
mqttClient.connect(connectOptions)
~~~
diff --git a/mqtt-client/api/mqtt-client.api b/mqtt-client/api/mqtt-client.api
index f0b0e04f..fcbcf07a 100644
--- a/mqtt-client/api/mqtt-client.api
+++ b/mqtt-client/api/mqtt-client.api
@@ -26,8 +26,8 @@ public abstract interface class com/gojek/mqtt/client/MqttInterceptor {
public final class com/gojek/mqtt/client/config/ExperimentConfigs {
public fun ()V
- public fun (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJ)V
- public synthetic fun (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZ)V
+ public synthetic fun (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lcom/gojek/mqtt/client/config/SubscriptionStore;
public final fun component2 ()Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;
public final fun component3 ()I
@@ -35,8 +35,9 @@ public final class com/gojek/mqtt/client/config/ExperimentConfigs {
public final fun component5 ()I
public final fun component6 ()J
public final fun component7 ()J
- public final fun copy (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJ)Lcom/gojek/mqtt/client/config/ExperimentConfigs;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/client/config/ExperimentConfigs;Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJILjava/lang/Object;)Lcom/gojek/mqtt/client/config/ExperimentConfigs;
+ public final fun component8 ()Z
+ public final fun copy (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZ)Lcom/gojek/mqtt/client/config/ExperimentConfigs;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/client/config/ExperimentConfigs;Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZILjava/lang/Object;)Lcom/gojek/mqtt/client/config/ExperimentConfigs;
public fun equals (Ljava/lang/Object;)Z
public final fun getActivityCheckIntervalSeconds ()I
public final fun getAdaptiveKeepAliveConfig ()Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;
@@ -44,13 +45,14 @@ public final class com/gojek/mqtt/client/config/ExperimentConfigs {
public final fun getIncomingMessagesCleanupIntervalSecs ()J
public final fun getIncomingMessagesTTLSecs ()J
public final fun getPolicyResetTimeSeconds ()I
+ public final fun getShouldUseNewSSLFlow ()Z
public final fun getSubscriptionStore ()Lcom/gojek/mqtt/client/config/SubscriptionStore;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
public abstract class com/gojek/mqtt/client/config/MqttConfiguration {
- public fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILjavax/net/SocketFactory;Lcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)V
+ public fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)V
public fun getAuthFailureHandler ()Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;
public fun getAuthenticator ()Lcom/gojek/mqtt/auth/Authenticator;
public fun getConnectRetryTimePolicy ()Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;
@@ -61,7 +63,6 @@ public abstract class com/gojek/mqtt/client/config/MqttConfiguration {
public fun getMqttInterceptorList ()Ljava/util/List;
public fun getPersistenceOptions ()Lcom/gojek/mqtt/client/config/PersistenceOptions;
public fun getPingSender ()Lcom/gojek/mqtt/pingsender/MqttPingSender;
- public fun getSocketFactory ()Ljavax/net/SocketFactory;
public fun getSubscriptionRetryPolicy ()Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;
public fun getUnsubscriptionRetryPolicy ()Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;
public fun getWakeLockTimeout ()I
@@ -94,24 +95,23 @@ public final class com/gojek/mqtt/client/config/SubscriptionStore : java/lang/En
}
public final class com/gojek/mqtt/client/config/v3/MqttV3Configuration : com/gojek/mqtt/client/config/MqttConfiguration {
- public fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILjavax/net/SocketFactory;Lcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)V
- public synthetic fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILjavax/net/SocketFactory;Lcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)V
+ public synthetic fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;
- public final fun component10 ()Lcom/gojek/mqtt/event/EventHandler;
- public final fun component11 ()Lcom/gojek/mqtt/pingsender/MqttPingSender;
- public final fun component12 ()Ljava/util/List;
- public final fun component13 ()Lcom/gojek/mqtt/client/config/PersistenceOptions;
- public final fun component14 ()Lcom/gojek/mqtt/client/config/ExperimentConfigs;
+ public final fun component10 ()Lcom/gojek/mqtt/pingsender/MqttPingSender;
+ public final fun component11 ()Ljava/util/List;
+ public final fun component12 ()Lcom/gojek/mqtt/client/config/PersistenceOptions;
+ public final fun component13 ()Lcom/gojek/mqtt/client/config/ExperimentConfigs;
public final fun component2 ()Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;
public final fun component3 ()Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;
public final fun component4 ()Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;
public final fun component5 ()I
- public final fun component6 ()Ljavax/net/SocketFactory;
- public final fun component7 ()Lcom/gojek/courier/logging/ILogger;
- public final fun component8 ()Lcom/gojek/mqtt/auth/Authenticator;
- public final fun component9 ()Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;
- public final fun copy (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILjavax/net/SocketFactory;Lcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILjavax/net/SocketFactory;Lcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;ILjava/lang/Object;)Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;
+ public final fun component6 ()Lcom/gojek/courier/logging/ILogger;
+ public final fun component7 ()Lcom/gojek/mqtt/auth/Authenticator;
+ public final fun component8 ()Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;
+ public final fun component9 ()Lcom/gojek/mqtt/event/EventHandler;
+ public final fun copy (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;ILjava/lang/Object;)Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;
public fun equals (Ljava/lang/Object;)Z
public fun getAuthFailureHandler ()Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;
public fun getAuthenticator ()Lcom/gojek/mqtt/auth/Authenticator;
@@ -123,7 +123,6 @@ public final class com/gojek/mqtt/client/config/v3/MqttV3Configuration : com/goj
public fun getMqttInterceptorList ()Ljava/util/List;
public fun getPersistenceOptions ()Lcom/gojek/mqtt/client/config/PersistenceOptions;
public fun getPingSender ()Lcom/gojek/mqtt/pingsender/MqttPingSender;
- public fun getSocketFactory ()Ljavax/net/SocketFactory;
public fun getSubscriptionRetryPolicy ()Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;
public fun getUnsubscriptionRetryPolicy ()Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;
public fun getWakeLockTimeout ()I
@@ -1012,6 +1011,7 @@ public final class com/gojek/mqtt/model/AdaptiveKeepAliveConfig {
}
public final class com/gojek/mqtt/model/KeepAlive {
+ public static final field Companion Lcom/gojek/mqtt/model/KeepAlive$Companion;
public fun (IZ)V
public synthetic fun (IZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()I
@@ -1023,32 +1023,49 @@ public final class com/gojek/mqtt/model/KeepAlive {
public fun toString ()Ljava/lang/String;
}
+public final class com/gojek/mqtt/model/KeepAlive$Companion {
+ public final fun getNO_KEEP_ALIVE ()Lcom/gojek/mqtt/model/KeepAlive;
+}
+
public final class com/gojek/mqtt/model/MqttConnectOptions {
- public fun (Ljava/util/List;Lcom/gojek/mqtt/model/KeepAlive;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILcom/gojek/mqtt/model/MqttVersion;Ljava/util/Map;)V
- public synthetic fun (Ljava/util/List;Lcom/gojek/mqtt/model/KeepAlive;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILcom/gojek/mqtt/model/MqttVersion;Ljava/util/Map;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Ljava/util/List;
- public final fun component2 ()Lcom/gojek/mqtt/model/KeepAlive;
- public final fun component3 ()Ljava/lang/String;
- public final fun component4 ()Ljava/lang/String;
- public final fun component5 ()Ljava/lang/String;
- public final fun component6 ()Z
- public final fun component7 ()I
- public final fun component8 ()Lcom/gojek/mqtt/model/MqttVersion;
- public final fun component9 ()Ljava/util/Map;
- public final fun copy (Ljava/util/List;Lcom/gojek/mqtt/model/KeepAlive;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILcom/gojek/mqtt/model/MqttVersion;Ljava/util/Map;)Lcom/gojek/mqtt/model/MqttConnectOptions;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/model/MqttConnectOptions;Ljava/util/List;Lcom/gojek/mqtt/model/KeepAlive;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILcom/gojek/mqtt/model/MqttVersion;Ljava/util/Map;ILjava/lang/Object;)Lcom/gojek/mqtt/model/MqttConnectOptions;
- public fun equals (Ljava/lang/Object;)Z
+ public static final field Companion Lcom/gojek/mqtt/model/MqttConnectOptions$Companion;
+ public synthetic fun (Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getClientId ()Ljava/lang/String;
+ public final fun getConnectionSpec ()Lorg/eclipse/paho/client/mqttv3/ConnectionSpec;
public final fun getKeepAlive ()Lcom/gojek/mqtt/model/KeepAlive;
public final fun getPassword ()Ljava/lang/String;
+ public final fun getProtocols ()Ljava/util/List;
public final fun getReadTimeoutSecs ()I
public final fun getServerUris ()Ljava/util/List;
+ public final fun getSocketFactory ()Ljavax/net/SocketFactory;
+ public final fun getSslSocketFactory ()Ljavax/net/ssl/SSLSocketFactory;
public final fun getUserPropertiesMap ()Ljava/util/Map;
public final fun getUsername ()Ljava/lang/String;
public final fun getVersion ()Lcom/gojek/mqtt/model/MqttVersion;
- public fun hashCode ()I
+ public final fun getX509TrustManager ()Ljavax/net/ssl/X509TrustManager;
public final fun isCleanSession ()Z
- public fun toString ()Ljava/lang/String;
+ public final fun newBuilder ()Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+}
+
+public final class com/gojek/mqtt/model/MqttConnectOptions$Builder {
+ public fun ()V
+ public final fun alpnProtocols (Ljava/util/List;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun build ()Lcom/gojek/mqtt/model/MqttConnectOptions;
+ public final fun cleanSession (Z)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun clientId (Ljava/lang/String;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun connectionSpec (Lorg/eclipse/paho/client/mqttv3/ConnectionSpec;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun keepAlive (Lcom/gojek/mqtt/model/KeepAlive;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun mqttVersion (Lcom/gojek/mqtt/model/MqttVersion;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun password (Ljava/lang/String;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun readTimeoutSecs (I)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun serverUris (Ljava/util/List;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun socketFactory (Ljavax/net/SocketFactory;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun sslSocketFactory (Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun userName (Ljava/lang/String;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun userProperties (Ljava/util/Map;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+}
+
+public final class com/gojek/mqtt/model/MqttConnectOptions$Companion {
}
public final class com/gojek/mqtt/model/MqttVersion : java/lang/Enum {
diff --git a/mqtt-client/build.gradle.kts b/mqtt-client/build.gradle.kts
index 2fd26cab..626500e4 100644
--- a/mqtt-client/build.gradle.kts
+++ b/mqtt-client/build.gradle.kts
@@ -53,6 +53,7 @@ dependencies {
testImplementation(deps.android.test.junit)
testImplementation(deps.android.test.mockito)
+ testImplementation(deps.android.test.mockitoCore)
androidTestImplementation(deps.android.test.junitExt)
}
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/ExperimentConfigs.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/ExperimentConfigs.kt
index ed49af0c..2f1d863d 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/ExperimentConfigs.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/ExperimentConfigs.kt
@@ -13,7 +13,8 @@ data class ExperimentConfigs(
val inactivityTimeoutSeconds: Int = DEFAULT_INACTIVITY_TIMEOUT_SECS,
val policyResetTimeSeconds: Int = DEFAULT_POLICY_RESET_TIME_SECS,
val incomingMessagesTTLSecs: Long = 360,
- val incomingMessagesCleanupIntervalSecs: Long = 60
+ val incomingMessagesCleanupIntervalSecs: Long = 60,
+ val shouldUseNewSSLFlow: Boolean = false
)
enum class SubscriptionStore {
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/MqttConfiguration.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/MqttConfiguration.kt
index abfbc30b..0a6c3f6b 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/MqttConfiguration.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/MqttConfiguration.kt
@@ -9,7 +9,6 @@ import com.gojek.mqtt.pingsender.MqttPingSender
import com.gojek.mqtt.policies.connectretrytime.IConnectRetryTimePolicy
import com.gojek.mqtt.policies.connecttimeout.IConnectTimeoutPolicy
import com.gojek.mqtt.policies.subscriptionretry.ISubscriptionRetryPolicy
-import javax.net.SocketFactory
abstract class MqttConfiguration(
open val connectRetryTimePolicy: IConnectRetryTimePolicy,
@@ -17,7 +16,6 @@ abstract class MqttConfiguration(
open val subscriptionRetryPolicy: ISubscriptionRetryPolicy,
open val unsubscriptionRetryPolicy: ISubscriptionRetryPolicy,
open val wakeLockTimeout: Int,
- open val socketFactory: SocketFactory?,
open val logger: ILogger,
open val authenticator: Authenticator,
open val authFailureHandler: AuthFailureHandler?,
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/v3/MqttV3Configuration.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/v3/MqttV3Configuration.kt
index d7457a2e..39dd9c2a 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/v3/MqttV3Configuration.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/v3/MqttV3Configuration.kt
@@ -22,7 +22,6 @@ import com.gojek.mqtt.policies.connecttimeout.IConnectTimeoutPolicy
import com.gojek.mqtt.policies.subscriptionretry.ISubscriptionRetryPolicy
import com.gojek.mqtt.policies.subscriptionretry.SubscriptionRetryConfig
import com.gojek.mqtt.policies.subscriptionretry.SubscriptionRetryPolicy
-import javax.net.SocketFactory
data class MqttV3Configuration(
override val connectRetryTimePolicy: IConnectRetryTimePolicy =
@@ -34,7 +33,6 @@ data class MqttV3Configuration(
override val unsubscriptionRetryPolicy: ISubscriptionRetryPolicy =
SubscriptionRetryPolicy(SubscriptionRetryConfig()),
override val wakeLockTimeout: Int = DEFAULT_WAKELOCK_TIMEOUT,
- override val socketFactory: SocketFactory? = null,
override val logger: ILogger = NoOpLogger(),
override val authenticator: Authenticator,
override val authFailureHandler: AuthFailureHandler? = null,
@@ -49,7 +47,6 @@ data class MqttV3Configuration(
subscriptionRetryPolicy = subscriptionRetryPolicy,
unsubscriptionRetryPolicy = unsubscriptionRetryPolicy,
wakeLockTimeout = wakeLockTimeout,
- socketFactory = socketFactory,
logger = logger,
authenticator = authenticator,
authFailureHandler = authFailureHandler,
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
index 6963419a..757403f8 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
@@ -171,13 +171,13 @@ internal class AndroidMqttClient(
maxInflightMessages = MAX_INFLIGHT_MESSAGES_ALLOWED,
logger = mqttConfiguration.logger,
connectionEventHandler = mqttClientEventAdapter.adapt(),
- socketFactory = mqttConfiguration.socketFactory,
mqttInterceptorList = mqttConfiguration.mqttInterceptorList.map {
mapToPahoInterceptor(it)
},
persistenceOptions = mqttConfiguration.persistenceOptions,
inactivityTimeoutSeconds = experimentConfigs.inactivityTimeoutSeconds,
- policyResetTimeSeconds = experimentConfigs.policyResetTimeSeconds
+ policyResetTimeSeconds = experimentConfigs.policyResetTimeSeconds,
+ shouldUseNewSSLFlow = experimentConfigs.shouldUseNewSSLFlow
)
mqttConnection = MqttConnection(
@@ -506,15 +506,15 @@ internal class AndroidMqttClient(
forceRefresh = false
this.hostFallbackPolicy = HostFallbackPolicy(connectOptions.serverUris)
val mqttConnectOptions = if (isAdaptiveKAConnection) {
- connectOptions.copy(
- keepAlive = keepAliveProvider.getKeepAlive(connectOptions),
- clientId = connectOptions.clientId + ":adaptive",
- isCleanSession = true
- )
+ connectOptions.newBuilder()
+ .keepAlive(keepAliveProvider.getKeepAlive(connectOptions))
+ .clientId(connectOptions.clientId + ":adaptive")
+ .cleanSession(true)
+ .build()
} else {
- connectOptions.copy(
- keepAlive = keepAliveProvider.getKeepAlive(connectOptions)
- )
+ connectOptions.newBuilder()
+ .keepAlive(keepAliveProvider.getKeepAlive(connectOptions))
+ .build()
}
if (isAdaptiveKAConnection.not()) {
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/connection/MqttConnection.kt b/mqtt-client/src/main/java/com/gojek/mqtt/connection/MqttConnection.kt
index 69c4b03b..804bb047 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/connection/MqttConnection.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/connection/MqttConnection.kt
@@ -162,27 +162,26 @@ internal class MqttConnection(
if (options == null) {
options = MqttConnectOptions()
}
- // Setting some connection options which we need to reset on every connect
- if (isSSL()) {
- options!!.socketFactory = connectionConfig.socketFactory
- } else {
- options!!.socketFactory = null
- }
- options!!.userName = connectOptions.username
- options!!.password = connectOptions.password.toCharArray()
- options!!.isCleanSession = connectOptions.isCleanSession
- options!!.keepAliveInterval = connectOptions.keepAlive.timeSeconds
- options!!.keepAliveIntervalServer = connectOptions.keepAlive.timeSeconds
- options!!.readTimeout = if (connectOptions.readTimeoutSecs == -1) {
- connectOptions.keepAlive.timeSeconds + 60
- } else {
- connectOptions.readTimeoutSecs
+ options!!.apply {
+ userName = connectOptions.username
+ password = connectOptions.password.toCharArray()
+ isCleanSession = connectOptions.isCleanSession
+ keepAliveInterval = connectOptions.keepAlive.timeSeconds
+ keepAliveIntervalServer = connectOptions.keepAlive.timeSeconds
+ readTimeout = connectOptions.readTimeoutSecs
+ connectionTimeout = connectTimeoutPolicy.getConnectTimeOut()
+ handshakeTimeout = connectTimeoutPolicy.getHandshakeTimeOut()
+ protocolName = mqttConnectOptions.version.protocolName
+ protocolLevel = mqttConnectOptions.version.protocolLevel
+ userPropertyList = getUserPropertyList(connectOptions.userPropertiesMap)
+ socketFactory = mqttConnectOptions.socketFactory
+ sslSocketFactory = mqttConnectOptions.sslSocketFactory
+ x509TrustManager = mqttConnectOptions.x509TrustManager
+ connectionSpec = mqttConnectOptions.connectionSpec
+ alpnProtocolList = mqttConnectOptions.protocols
}
- options!!.connectionTimeout = connectTimeoutPolicy.getConnectTimeOut()
- options!!.handshakeTimeout = connectTimeoutPolicy.getHandshakeTimeOut()
- options!!.protocolName = mqttConnectOptions.version.protocolName
- options!!.protocolLevel = mqttConnectOptions.version.protocolLevel
- options!!.userPropertyList = getUserPropertyList(connectOptions.userPropertiesMap)
+ // Setting some connection options which we need to reset on every connect
+
logger.d(TAG, "MQTT connecting on : " + mqtt!!.serverURI)
updatePolicyParams = true
connectStartTime = clock.nanoTime()
@@ -652,6 +651,10 @@ internal class MqttConnection(
override fun inactivityTimeoutSecs(): Int {
return connectionConfig.inactivityTimeoutSeconds
}
+
+ override fun useNewSSLFlow(): Boolean {
+ return connectionConfig.shouldUseNewSSLFlow
+ }
}
}
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/connection/config/v3/ConnectionConfig.kt b/mqtt-client/src/main/java/com/gojek/mqtt/connection/config/v3/ConnectionConfig.kt
index 70fbe574..8329b27c 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/connection/config/v3/ConnectionConfig.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/connection/config/v3/ConnectionConfig.kt
@@ -8,7 +8,6 @@ import com.gojek.mqtt.constants.QUIESCE_TIME_MILLIS
import com.gojek.mqtt.policies.connectretrytime.IConnectRetryTimePolicy
import com.gojek.mqtt.policies.connecttimeout.IConnectTimeoutPolicy
import com.gojek.mqtt.policies.subscriptionretry.ISubscriptionRetryPolicy
-import javax.net.SocketFactory
import org.eclipse.paho.client.mqttv3.MqttInterceptor
internal data class ConnectionConfig(
@@ -19,12 +18,12 @@ internal data class ConnectionConfig(
val wakeLockTimeout: Int,
val maxInflightMessages: Int,
val logger: ILogger,
- val socketFactory: SocketFactory?,
val connectionEventHandler: ConnectionEventHandler,
val quiesceTimeout: Int = QUIESCE_TIME_MILLIS,
val disconnectTimeout: Int = DISCONNECT_TIMEOUT_MILLIS,
val mqttInterceptorList: List,
val persistenceOptions: PersistenceOptions,
val inactivityTimeoutSeconds: Int,
- val policyResetTimeSeconds: Int
+ val policyResetTimeSeconds: Int,
+ val shouldUseNewSSLFlow: Boolean
)
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/model/KeepAlive.kt b/mqtt-client/src/main/java/com/gojek/mqtt/model/KeepAlive.kt
index 6ea17cdf..0e59d48e 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/model/KeepAlive.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/model/KeepAlive.kt
@@ -3,4 +3,8 @@ package com.gojek.mqtt.model
data class KeepAlive(
val timeSeconds: Int,
internal val isOptimal: Boolean = false
-)
+) {
+ companion object {
+ val NO_KEEP_ALIVE = KeepAlive(timeSeconds = 60, isOptimal = false)
+ }
+}
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt b/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
index 5aa83e0e..69592f2f 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
@@ -1,18 +1,220 @@
package com.gojek.mqtt.model
+import com.gojek.mqtt.model.KeepAlive.Companion.NO_KEEP_ALIVE
import com.gojek.mqtt.model.MqttVersion.VERSION_3_1_1
+import javax.net.SocketFactory
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+import org.eclipse.paho.client.mqttv3.ConnectionSpec
+import org.eclipse.paho.client.mqttv3.Protocol
+import org.eclipse.paho.client.mqttv3.internal.platform.Platform
-data class MqttConnectOptions(
- val serverUris: List,
- val keepAlive: KeepAlive,
- val clientId: String,
- val username: String,
- val password: String,
- val isCleanSession: Boolean,
- val readTimeoutSecs: Int = -1,
- val version: MqttVersion = VERSION_3_1_1,
- val userPropertiesMap: Map = emptyMap()
-)
+class MqttConnectOptions private constructor(
+ builder: Builder
+) {
+ val serverUris: List = builder.serverUris
+
+ val keepAlive: KeepAlive = builder.keepAlive
+
+ val clientId: String = builder.clientId
+
+ val username: String = builder.username
+
+ val password: String = builder.password
+
+ val isCleanSession: Boolean = builder.isCleanSession
+
+ val readTimeoutSecs: Int
+
+ val version: MqttVersion = builder.version
+
+ val userPropertiesMap: Map = builder.userPropertiesMap
+
+ val socketFactory: SocketFactory = builder.socketFactory
+
+ val sslSocketFactory: SSLSocketFactory?
+
+ val x509TrustManager: X509TrustManager?
+
+ val connectionSpec: ConnectionSpec =
+ builder.connectionSpec
+
+ val protocols: List = builder.protocols
+
+ init {
+ if (connectionSpec.isTls.not()) {
+ this.sslSocketFactory = null
+ this.x509TrustManager = null
+ } else if (builder.sslSocketFactoryOrNull != null) {
+ this.sslSocketFactory = builder.sslSocketFactoryOrNull
+ this.x509TrustManager = builder.x509TrustManagerOrNull!!
+ } else {
+ this.x509TrustManager = Platform.get().platformTrustManager()
+ this.sslSocketFactory = Platform.get().newSslSocketFactory(x509TrustManager!!)
+ }
+
+ this.readTimeoutSecs = if (builder.readTimeoutSecs < builder.keepAlive.timeSeconds) {
+ builder.keepAlive.timeSeconds + 60
+ } else {
+ builder.readTimeoutSecs
+ }
+ }
+
+ fun newBuilder(): Builder = Builder(this)
+
+ class Builder() {
+ internal var serverUris: List = emptyList()
+ internal var keepAlive: KeepAlive = NO_KEEP_ALIVE
+ internal var clientId: String = ""
+ internal var username: String = ""
+ internal var password: String = ""
+ internal var isCleanSession: Boolean = false
+ internal var readTimeoutSecs: Int = DEFAULT_READ_TIMEOUT
+ internal var version: MqttVersion = VERSION_3_1_1
+ internal var userPropertiesMap: Map = emptyMap()
+ internal var socketFactory: SocketFactory = SocketFactory.getDefault()
+ internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
+ internal var x509TrustManagerOrNull: X509TrustManager? = null
+ internal var connectionSpec: ConnectionSpec = DEFAULT_CONNECTION_SPECS
+ internal var protocols: List = emptyList()
+
+ internal constructor(mqttConnectOptions: MqttConnectOptions) : this() {
+ this.serverUris = mqttConnectOptions.serverUris
+ this.keepAlive = mqttConnectOptions.keepAlive
+ this.clientId = mqttConnectOptions.clientId
+ this.username = mqttConnectOptions.username
+ this.password = mqttConnectOptions.password
+ this.isCleanSession = mqttConnectOptions.isCleanSession
+ this.readTimeoutSecs = mqttConnectOptions.readTimeoutSecs
+ this.version = mqttConnectOptions.version
+ this.userPropertiesMap = mqttConnectOptions.userPropertiesMap
+ this.socketFactory = mqttConnectOptions.socketFactory
+ this.sslSocketFactoryOrNull = mqttConnectOptions.sslSocketFactory
+ this.x509TrustManagerOrNull = mqttConnectOptions.x509TrustManager
+ this.connectionSpec = mqttConnectOptions.connectionSpec
+ this.protocols = mqttConnectOptions.protocols
+ }
+
+ fun serverUris(serverUris: List) = apply {
+ require(serverUris.isNotEmpty()) { "serverUris cannot be empty" }
+ this.serverUris = serverUris
+ }
+
+ fun keepAlive(keepAlive: KeepAlive) = apply {
+ require(keepAlive.timeSeconds > 0) { "keepAlive timeSeconds must be >0" }
+ this.keepAlive = keepAlive
+ }
+
+ fun clientId(clientId: String) = apply {
+ require(clientId.isNotEmpty()) { "clientId cannot be empty" }
+ this.clientId = clientId
+ }
+
+ fun userName(username: String) = apply {
+ require(username.isNotEmpty()) { "username cannot be empty" }
+ this.username = username
+ }
+
+ fun password(password: String) = apply {
+ this.password = password
+ }
+
+ fun cleanSession(cleanSession: Boolean) = apply {
+ this.isCleanSession = cleanSession
+ }
+
+ fun readTimeoutSecs(readTimeoutSecs: Int) = apply {
+ require(readTimeoutSecs > 0) { "read timeout should be > 0" }
+ this.readTimeoutSecs = readTimeoutSecs
+ }
+
+ fun mqttVersion(mqttVersion: MqttVersion) = apply {
+ this.version = mqttVersion
+ }
+
+ fun userProperties(userProperties: Map) = apply {
+ this.userPropertiesMap = userProperties.toMap()
+ }
+
+ /**
+ * Sets the socket factory used to create connections.
+ *
+ * If unset, the [system-wide default][SocketFactory.getDefault] socket factory will be used.
+ */
+ fun socketFactory(socketFactory: SocketFactory) = apply {
+ require(socketFactory !is SSLSocketFactory) { "socketFactory instanceof SSLSocketFactory" }
+
+ this.socketFactory = socketFactory
+ }
+
+ /**
+ * Sets the socket factory and trust manager used to secure MQTT/Websocket connections. If unset, the
+ * system defaults will be used.
+ *
+ * Most applications should not call this method, and instead use the system defaults. Those
+ * classes include special optimizations that can be lost if the implementations are decorated.
+ *
+ * If necessary, you can create and configure the defaults yourself with the following code:
+ *
+ * ```java
+ * TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
+ * TrustManagerFactory.getDefaultAlgorithm());
+ * trustManagerFactory.init((KeyStore) null);
+ * TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
+ * if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
+ * throw new IllegalStateException("Unexpected default trust managers:"
+ * + Arrays.toString(trustManagers));
+ * }
+ * X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
+ *
+ * SSLContext sslContext = SSLContext.getInstance("TLS");
+ * sslContext.init(null, new TrustManager[] { trustManager }, null);
+ * SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+ *
+ * MQTTConnectOptions client = MQTTConnectOptions.Builder()
+ * .sslSocketFactory(sslSocketFactory, trustManager)
+ * .build();
+ * ```
+ *
+ * ## TrustManagers on Android are Weird!
+ *
+ * Trust managers targeting Android must also define a method that has this signature:
+ *
+ * ```java
+ * @SuppressWarnings("unused")
+ * public List checkServerTrusted(
+ * X509Certificate[] chain, String authType, String host) throws CertificateException {
+ * }
+ * ```
+ * See [android.net.http.X509TrustManagerExtensions] for more information.
+ */
+ fun sslSocketFactory(
+ sslSocketFactory: SSLSocketFactory,
+ trustManager: X509TrustManager
+ ) = apply {
+ this.sslSocketFactoryOrNull = sslSocketFactory
+ this.x509TrustManagerOrNull = trustManager
+ }
+
+ fun connectionSpec(connectionSpec: ConnectionSpec) = apply {
+ this.connectionSpec = connectionSpec
+ }
+
+ fun alpnProtocols(protocols: List) = apply {
+ require(protocols.isNotEmpty()) { "alpn protocol list cannot be empty" }
+ this.protocols = protocols
+ }
+
+ fun build(): MqttConnectOptions = MqttConnectOptions(this)
+ }
+
+ companion object {
+
+ internal const val DEFAULT_READ_TIMEOUT = -1
+
+ internal val DEFAULT_CONNECTION_SPECS = ConnectionSpec.MODERN_TLS
+ }
+}
enum class MqttVersion(internal val protocolName: String, internal val protocolLevel: Int) {
VERSION_3_1("MQIsdp", 3), VERSION_3_1_1("MQTT", 4)
diff --git a/mqtt-client/src/test/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImplTest.kt b/mqtt-client/src/test/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImplTest.kt
index c69e942d..abe8c35f 100644
--- a/mqtt-client/src/test/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImplTest.kt
+++ b/mqtt-client/src/test/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImplTest.kt
@@ -6,7 +6,6 @@ import com.gojek.mqtt.policies.connectretrytime.IConnectRetryTimePolicy
import com.gojek.mqtt.scheduler.IRunnableScheduler
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
-import com.nhaarman.mockitokotlin2.verifyZeroInteractions
import com.nhaarman.mockitokotlin2.whenever
import java.net.SocketException
import java.net.SocketTimeoutException
@@ -40,6 +39,7 @@ import org.eclipse.paho.client.mqttv3.MqttException.REASON_CODE_TOKEN_INUSE
import org.eclipse.paho.client.mqttv3.MqttException.REASON_CODE_UNEXPECTED_ERROR
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.verifyNoInteractions
import org.mockito.junit.MockitoJUnitRunner
@RunWith(MockitoJUnitRunner::class)
@@ -177,7 +177,7 @@ class MqttExceptionHandlerImplTest {
fun `test exception with reason code 32101 with reconnect=false`() {
val exception = MqttException(REASON_CODE_CLIENT_ALREADY_DISCONNECTED.toInt())
mqttExceptionHandlerImpl.handleException(exception, false)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
@@ -191,7 +191,7 @@ class MqttExceptionHandlerImplTest {
fun `test exception with reason code 32102 with reconnect=false`() {
val exception = MqttException(REASON_CODE_CLIENT_DISCONNECTING.toInt())
mqttExceptionHandlerImpl.handleException(exception, false)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
@@ -205,7 +205,7 @@ class MqttExceptionHandlerImplTest {
fun `test exception with reason code 32104 with reconnect=false`() {
val exception = MqttException(REASON_CODE_CLIENT_NOT_CONNECTED.toInt())
mqttExceptionHandlerImpl.handleException(exception, false)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
@@ -219,14 +219,14 @@ class MqttExceptionHandlerImplTest {
fun `test exception with reason code 32000 with reconnect=false`() {
val exception = MqttException(REASON_CODE_CLIENT_TIMEOUT.toInt())
mqttExceptionHandlerImpl.handleException(exception, false)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32110`() {
val exception = MqttException(REASON_CODE_CONNECT_IN_PROGRESS.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
@@ -249,83 +249,83 @@ class MqttExceptionHandlerImplTest {
fun `test exception with reason code 32109 with reconnect=false`() {
val exception = MqttException(REASON_CODE_CONNECTION_LOST.toInt())
mqttExceptionHandlerImpl.handleException(exception, false)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32202`() {
val exception = MqttException(REASON_CODE_MAX_INFLIGHT.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32111`() {
val exception = MqttException(REASON_CODE_CLIENT_CLOSED.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32100`() {
val exception = MqttException(REASON_CODE_CLIENT_CONNECTED.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32107`() {
val exception = MqttException(REASON_CODE_CLIENT_DISCONNECT_PROHIBITED.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 2`() {
val exception = MqttException(REASON_CODE_INVALID_CLIENT_ID.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32108`() {
val exception = MqttException(REASON_CODE_INVALID_MESSAGE.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 1`() {
val exception = MqttException(REASON_CODE_INVALID_PROTOCOL_VERSION.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32001`() {
val exception = MqttException(REASON_CODE_NO_MESSAGE_IDS_AVAILABLE.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32105`() {
val exception = MqttException(REASON_CODE_SOCKET_FACTORY_MISMATCH.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32106`() {
val exception = MqttException(REASON_CODE_SSL_CONFIG_ERROR.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
@Test
fun `test exception with reason code 32201`() {
val exception = MqttException(REASON_CODE_TOKEN_INUSE.toInt())
mqttExceptionHandlerImpl.handleException(exception, true)
- verifyZeroInteractions(runnableScheduler, connectRetryTimePolicy)
+ verifyNoInteractions(runnableScheduler, connectRetryTimePolicy)
}
}
diff --git a/network-tracker/build.gradle.kts b/network-tracker/build.gradle.kts
index 592d4260..770282ce 100644
--- a/network-tracker/build.gradle.kts
+++ b/network-tracker/build.gradle.kts
@@ -28,6 +28,7 @@ dependencies {
api(project(":courier-core"))
implementation(deps.android.androidx.coreKtx)
+ testImplementation(deps.android.test.mockitoCore)
testImplementation(deps.android.test.kotlinTestJunit)
}
diff --git a/paho/build.gradle.kts b/paho/build.gradle.kts
index 237b0b34..6ef57762 100644
--- a/paho/build.gradle.kts
+++ b/paho/build.gradle.kts
@@ -16,12 +16,20 @@ plugins {
}
java {
- sourceCompatibility = JavaVersion.VERSION_1_8
- targetCompatibility = JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
}
dependencies {
implementation(deps.kotlin.stdlib.core)
+ implementation("com.squareup.okio:okio:3.2.0")
+
+ compileOnly("org.robolectric:android-all:13-robolectric-9030017")
+ compileOnly("org.bouncycastle:bcprov-jdk15to18:1.71")
+ compileOnly("org.bouncycastle:bctls-jdk15to18:1.71")
+ compileOnly("org.conscrypt:conscrypt-openjdk-uber:2.5.2")
+ compileOnly("org.openjsse:openjsse:1.1.10")
+
testImplementation(deps.android.test.kotlinTestJunit)
}
diff --git a/paho/src/main/AndroidManifest.xml b/paho/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..17e0e3ec
--- /dev/null
+++ b/paho/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/ConnectionSpec.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/ConnectionSpec.kt
new file mode 100644
index 00000000..7e48192f
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/ConnectionSpec.kt
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2014 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3
+
+import java.util.Arrays
+import java.util.Objects
+import javax.net.ssl.SSLSocket
+import org.eclipse.paho.client.mqttv3.ConnectionSpec.Builder
+import org.eclipse.paho.client.mqttv3.internal.tls.CipherSuite
+import org.eclipse.paho.client.mqttv3.internal.tls.TlsVersion
+
+/**
+ * Specifies configuration for the socket connection that HTTP traffic travels through. For `https:`
+ * URLs, this includes the TLS version and cipher suites to use when negotiating a secure
+ * connection.
+ *
+ * The TLS versions configured in a connection spec are only be used if they are also enabled in the
+ * SSL socket. For example, if an SSL socket does not have TLS 1.3 enabled, it will not be used even
+ * if it is present on the connection spec. The same policy also applies to cipher suites.
+ *
+ * Use [Builder.allEnabledTlsVersions] and [Builder.allEnabledCipherSuites] to defer all feature
+ * selection to the underlying SSL socket.
+ *
+ * The configuration of each spec changes with each OkHttp release. This is annoying: upgrading
+ * your OkHttp library can break connectivity to certain web servers! But it’s a necessary annoyance
+ * because the TLS ecosystem is dynamic and staying up to date is necessary to stay secure. See
+ * [OkHttp's TLS Configuration History][tls_history] to track these changes.
+ *
+ * [tls_history]: https://square.github.io/okhttp/tls_configuration_history/
+ */
+class ConnectionSpec internal constructor(
+ @get:JvmName("isTls") val isTls: Boolean,
+ @get:JvmName("supportsTlsExtensions") val supportsTlsExtensions: Boolean,
+ internal val cipherSuitesAsString: Array?,
+ private val tlsVersionsAsString: Array?
+) {
+
+ /**
+ * Returns the cipher suites to use for a connection. Returns null if all of the SSL socket's
+ * enabled cipher suites should be used.
+ */
+ @get:JvmName("cipherSuites")
+ val cipherSuites: List?
+ get() {
+ return cipherSuitesAsString?.map { CipherSuite.forJavaName(it) }?.toList()
+ }
+
+ @JvmName("-deprecated_cipherSuites")
+ @Deprecated(
+ message = "moved to val",
+ replaceWith = ReplaceWith(expression = "cipherSuites"),
+ level = DeprecationLevel.ERROR
+ )
+ fun cipherSuites(): List? = cipherSuites
+
+ /**
+ * Returns the TLS versions to use when negotiating a connection. Returns null if all of the SSL
+ * socket's enabled TLS versions should be used.
+ */
+ @get:JvmName("tlsVersions")
+ val tlsVersions: List?
+ get() {
+ return tlsVersionsAsString?.map { TlsVersion.forJavaName(it) }?.toList()
+ }
+
+ @JvmName("-deprecated_tlsVersions")
+ @Deprecated(
+ message = "moved to val",
+ replaceWith = ReplaceWith(expression = "tlsVersions"),
+ level = DeprecationLevel.ERROR
+ )
+ fun tlsVersions(): List? = tlsVersions
+
+ @JvmName("-deprecated_supportsTlsExtensions")
+ @Deprecated(
+ message = "moved to val",
+ replaceWith = ReplaceWith(expression = "supportsTlsExtensions"),
+ level = DeprecationLevel.ERROR
+ )
+ fun supportsTlsExtensions(): Boolean = supportsTlsExtensions
+
+ /** Applies this spec to [sslSocket]. */
+ fun apply(sslSocket: SSLSocket, isFallback: Boolean) {
+ val specToApply = supportedSpec(sslSocket, isFallback)
+
+ if (specToApply.tlsVersions != null) {
+ sslSocket.enabledProtocols = specToApply.tlsVersionsAsString
+ }
+
+ if (specToApply.cipherSuites != null) {
+ sslSocket.enabledCipherSuites = specToApply.cipherSuitesAsString
+ }
+ }
+
+ /**
+ * Returns a copy of this that omits cipher suites and TLS versions not enabled by [sslSocket].
+ */
+ private fun supportedSpec(sslSocket: SSLSocket, isFallback: Boolean): ConnectionSpec {
+ val socketEnabledCipherSuites = sslSocket.enabledCipherSuites
+ var cipherSuitesIntersection: Array =
+ effectiveCipherSuites(socketEnabledCipherSuites)
+
+ val tlsVersionsIntersection = if (tlsVersionsAsString != null) {
+ sslSocket.enabledProtocols.intersect(tlsVersionsAsString, naturalOrder())
+ } else {
+ sslSocket.enabledProtocols
+ }
+
+ // In accordance with https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00 the SCSV
+ // cipher is added to signal that a protocol fallback has taken place.
+ val supportedCipherSuites = sslSocket.supportedCipherSuites
+ val indexOfFallbackScsv = supportedCipherSuites.indexOf(
+ "TLS_FALLBACK_SCSV",
+ CipherSuite.ORDER_BY_NAME
+ )
+ if (isFallback && indexOfFallbackScsv != -1) {
+ cipherSuitesIntersection = cipherSuitesIntersection.concat(
+ supportedCipherSuites[indexOfFallbackScsv]
+ )
+ }
+
+ return Builder(this)
+ .cipherSuites(*cipherSuitesIntersection)
+ .tlsVersions(*tlsVersionsIntersection)
+ .build()
+ }
+
+ /**
+ * Returns `true` if the socket, as currently configured, supports this connection spec. In
+ * order for a socket to be compatible the enabled cipher suites and protocols must intersect.
+ *
+ * For cipher suites, at least one of the [required cipher suites][cipherSuites] must match the
+ * socket's enabled cipher suites. If there are no required cipher suites the socket must have at
+ * least one cipher suite enabled.
+ *
+ * For protocols, at least one of the [required protocols][tlsVersions] must match the socket's
+ * enabled protocols.
+ */
+ fun isCompatible(socket: SSLSocket): Boolean {
+ if (!isTls) {
+ return false
+ }
+
+ if (tlsVersionsAsString != null &&
+ !tlsVersionsAsString.hasIntersection(socket.enabledProtocols, naturalOrder())
+ ) {
+ return false
+ }
+
+ if (cipherSuitesAsString != null && !cipherSuitesAsString.hasIntersection(
+ socket.enabledCipherSuites,
+ CipherSuite.ORDER_BY_NAME
+ )
+ ) {
+ return false
+ }
+
+ return true
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is ConnectionSpec) return false
+ if (other === this) return true
+
+ if (this.isTls != other.isTls) return false
+
+ if (isTls) {
+ if (!Arrays.equals(this.cipherSuitesAsString, other.cipherSuitesAsString)) return false
+ if (!Arrays.equals(this.tlsVersionsAsString, other.tlsVersionsAsString)) return false
+ if (this.supportsTlsExtensions != other.supportsTlsExtensions) return false
+ }
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = 17
+ if (isTls) {
+ result = 31 * result + (cipherSuitesAsString?.contentHashCode() ?: 0)
+ result = 31 * result + (tlsVersionsAsString?.contentHashCode() ?: 0)
+ result = 31 * result + if (supportsTlsExtensions) 0 else 1
+ }
+ return result
+ }
+
+ override fun toString(): String {
+ if (!isTls) return "ConnectionSpec()"
+
+ return (
+ "ConnectionSpec(" +
+ "cipherSuites=${Objects.toString(cipherSuites, "[all enabled]")}, " +
+ "tlsVersions=${Objects.toString(tlsVersions, "[all enabled]")}, " +
+ "supportsTlsExtensions=$supportsTlsExtensions)"
+ )
+ }
+
+ class Builder {
+ internal var tls: Boolean = false
+ internal var cipherSuites: Array? = null
+ internal var tlsVersions: Array? = null
+ internal var supportsTlsExtensions: Boolean = false
+
+ internal constructor(tls: Boolean) {
+ this.tls = tls
+ }
+
+ constructor(connectionSpec: ConnectionSpec) {
+ this.tls = connectionSpec.isTls
+ this.cipherSuites = connectionSpec.cipherSuitesAsString
+ this.tlsVersions = connectionSpec.tlsVersionsAsString
+ this.supportsTlsExtensions = connectionSpec.supportsTlsExtensions
+ }
+
+ fun allEnabledCipherSuites() = apply {
+ require(tls) { "no cipher suites for cleartext connections" }
+ this.cipherSuites = null
+ }
+
+ fun cipherSuites(vararg cipherSuites: CipherSuite): Builder = apply {
+ require(tls) { "no cipher suites for cleartext connections" }
+ val strings = cipherSuites.map { it.javaName }.toTypedArray()
+ return cipherSuites(*strings)
+ }
+
+ fun cipherSuites(vararg cipherSuites: String) = apply {
+ require(tls) { "no cipher suites for cleartext connections" }
+ require(cipherSuites.isNotEmpty()) { "At least one cipher suite is required" }
+
+ this.cipherSuites = cipherSuites.clone() as Array // Defensive copy.
+ }
+
+ fun allEnabledTlsVersions() = apply {
+ require(tls) { "no TLS versions for cleartext connections" }
+ this.tlsVersions = null
+ }
+
+ fun tlsVersions(vararg tlsVersions: TlsVersion): Builder = apply {
+ require(tls) { "no TLS versions for cleartext connections" }
+
+ val strings = tlsVersions.map { it.javaName }.toTypedArray()
+ return tlsVersions(*strings)
+ }
+
+ fun tlsVersions(vararg tlsVersions: String) = apply {
+ require(tls) { "no TLS versions for cleartext connections" }
+ require(tlsVersions.isNotEmpty()) { "At least one TLS version is required" }
+
+ this.tlsVersions = tlsVersions.clone() as Array // Defensive copy.
+ }
+
+ @Deprecated(
+ "since OkHttp 3.13 all TLS-connections are expected to support TLS extensions.\n" +
+ "In a future release setting this to true will be unnecessary and setting it to false\n" +
+ "will have no effect."
+ )
+ fun supportsTlsExtensions(supportsTlsExtensions: Boolean) = apply {
+ require(tls) { "no TLS extensions for cleartext connections" }
+ this.supportsTlsExtensions = supportsTlsExtensions
+ }
+
+ fun build(): ConnectionSpec = ConnectionSpec(
+ tls,
+ supportsTlsExtensions,
+ cipherSuites,
+ tlsVersions
+ )
+ }
+
+ @Suppress("DEPRECATION")
+ companion object {
+ // Most secure but generally supported list.
+ private val RESTRICTED_CIPHER_SUITES = arrayOf(
+ // TLSv1.3.
+ CipherSuite.TLS_AES_128_GCM_SHA256,
+ CipherSuite.TLS_AES_256_GCM_SHA384,
+ CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
+
+ // TLSv1.0, TLSv1.1, TLSv1.2.
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ )
+
+ // This is nearly equal to the cipher suites supported in Chrome 72, current as of 2019-02-24.
+ // See https://tinyurl.com/okhttp-cipher-suites for availability.
+ private val APPROVED_CIPHER_SUITES = arrayOf(
+ // TLSv1.3.
+ CipherSuite.TLS_AES_128_GCM_SHA256,
+ CipherSuite.TLS_AES_256_GCM_SHA384,
+ CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
+
+ // TLSv1.0, TLSv1.1, TLSv1.2.
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+
+ // Note that the following cipher suites are all on HTTP/2's bad cipher suites list. We'll
+ // continue to include them until better suites are commonly available.
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
+ CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ )
+
+ /** A secure TLS connection that requires a recent client platform and a recent server. */
+ @JvmField
+ val RESTRICTED_TLS = Builder(true)
+ .cipherSuites(*RESTRICTED_CIPHER_SUITES)
+ .tlsVersions(TlsVersion.TLS_1_3, TlsVersion.TLS_1_2)
+ .supportsTlsExtensions(true)
+ .build()
+
+ /**
+ * A modern TLS configuration that works on most client platforms and can connect to most servers.
+ * This is OkHttp's default configuration.
+ */
+ @JvmField
+ val MODERN_TLS = Builder(true)
+ .cipherSuites(*APPROVED_CIPHER_SUITES)
+ .tlsVersions(TlsVersion.TLS_1_3, TlsVersion.TLS_1_2)
+ .supportsTlsExtensions(true)
+ .build()
+
+ /**
+ * A backwards-compatible fallback configuration that works on obsolete client platforms and can
+ * connect to obsolete servers. When possible, prefer to upgrade your client platform or server
+ * rather than using this configuration.
+ */
+ @JvmField
+ val COMPATIBLE_TLS = Builder(true)
+ .cipherSuites(*APPROVED_CIPHER_SUITES)
+ .tlsVersions(
+ TlsVersion.TLS_1_3,
+ TlsVersion.TLS_1_2,
+ TlsVersion.TLS_1_1,
+ TlsVersion.TLS_1_0
+ )
+ .supportsTlsExtensions(true)
+ .build()
+
+ /** Unencrypted, unauthenticated connections for `http:` URLs. */
+ @JvmField
+ val CLEARTEXT = Builder(false).build()
+ }
+
+ private fun ConnectionSpec.effectiveCipherSuites(socketEnabledCipherSuites: Array): Array {
+ return if (cipherSuitesAsString != null) {
+ socketEnabledCipherSuites.intersect(cipherSuitesAsString, CipherSuite.ORDER_BY_NAME)
+ } else {
+ socketEnabledCipherSuites
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/IExperimentsConfig.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/IExperimentsConfig.java
index f64516bc..955afe43 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/IExperimentsConfig.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/IExperimentsConfig.java
@@ -2,4 +2,6 @@
public interface IExperimentsConfig {
int inactivityTimeoutSecs();
+
+ Boolean useNewSSLFlow();
}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttAsyncClient.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttAsyncClient.java
index 9675c2d6..45a8bf38 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttAsyncClient.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttAsyncClient.java
@@ -23,10 +23,12 @@
import org.eclipse.paho.client.mqttv3.internal.LocalNetworkModule;
import org.eclipse.paho.client.mqttv3.internal.NetworkModule;
import org.eclipse.paho.client.mqttv3.internal.SSLNetworkModule;
+import org.eclipse.paho.client.mqttv3.internal.SSLNetworkModuleV2;
import org.eclipse.paho.client.mqttv3.internal.TCPNetworkModule;
import org.eclipse.paho.client.mqttv3.internal.security.SSLSocketFactoryFactory;
import org.eclipse.paho.client.mqttv3.internal.websocket.WebSocketNetworkModule;
import org.eclipse.paho.client.mqttv3.internal.websocket.WebSocketSecureNetworkModule;
+import org.eclipse.paho.client.mqttv3.internal.websocket.WebSocketSecureNetworkModuleV2;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttDisconnect;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttPingReq;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttPublish;
@@ -35,17 +37,16 @@
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocketFactory;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
-import javax.net.SocketFactory;
-import javax.net.ssl.SSLSocketFactory;
-
/**
* Lightweight client for talking to an MQTT server using non-blocking methods that allow an operation to run in the background.
- *
+ *
*
* This class implements the non-blocking {@link IMqttAsyncClient} client interface allowing applications to initiate MQTT actions and then carry on working while the MQTT action
* completes on a background thread. This implementation is compatible with all Java SE runtimes from 1.4.2 and up.
@@ -72,7 +73,7 @@
*
* The message store interface is pluggable. Different stores can be used by implementing the {@link MqttClientPersistence} interface and passing it to the clients constructor.
*
- *
+ *
* @see IMqttAsyncClient
*/
public class MqttAsyncClient implements IMqttAsyncClient
@@ -101,6 +102,8 @@ public class MqttAsyncClient implements IMqttAsyncClient
private IPahoEvents pahoEvents;
+ private IExperimentsConfig experimentsConfig;
+
final static String className = MqttAsyncClient.class.getName();
final private String TAG = "MqttAsyncClient";
@@ -110,13 +113,13 @@ public class MqttAsyncClient implements IMqttAsyncClient
*
* The address of a server can be specified on the constructor. Alternatively a list containing one or more servers can be specified using the
* {@link MqttConnectOptions#setServerURIs(String[]) setServerURIs} method on MqttConnectOptions.
- *
+ *
*
* The serverURI
parameter is typically used with the the clientId
parameter to form a key. The key is used to store and reference messages while they
* are being delivered. Hence the serverURI specified on the constructor must still be specified even if a list of servers is specified on an MqttConnectOptions object. The
* serverURI on the constructor must remain the same across restarts of the client for delivery of messages to be maintained from a given client to a given server or set of
* servers.
- *
+ *
*
* The address of the server to connect to is specified as a URI. Two types of connection are supported tcp://
for a TCP connection and ssl://
for a
* TCP connection secured by SSL/TLS. For example:
@@ -126,7 +129,7 @@ public class MqttAsyncClient implements IMqttAsyncClient
*
* If the port is not specified, it will default to 1883 for tcp://
" URIs, and 8883 for ssl://
URIs.
*
- *
+ *
*
* A client identifier clientId
must be specified and be less that 65535 characters. It must be unique across all clients connecting to the same server. The
* clientId is used by the server to store data related to the client, hence it is important that the clientId remain the same when connecting to a server if durable
@@ -145,15 +148,15 @@ public class MqttAsyncClient implements IMqttAsyncClient
*
SSL Properties - applications can supply SSL settings as a simple Java Properties using {@link MqttConnectOptions#setSSLProperties(Properties)}.
* Use JVM settings - There are a number of standard Java system properties that can be used to configure key and trust stores.
*
- *
+ *
*
* In Java ME, the platform settings are used for SSL connections.
*
- *
+ *
*
* An instance of the default persistence mechanism {@link MqttDefaultFilePersistence} is used by the client. To specify a different persistence mechanism or to turn off
* persistence, use the {@link #MqttAsyncClient(String, String, MqttClientPersistence)} constructor.
- *
+ *
* @param serverURI
* the address of the server to connect to, specified as a URI. Can be overridden using {@link MqttConnectOptions#setServerURIs(String[])}
* @param clientId
@@ -194,13 +197,13 @@ public MqttAsyncClient(
*
* The address of a server can be specified on the constructor. Alternatively a list containing one or more servers can be specified using the
* {@link MqttConnectOptions#setServerURIs(String[]) setServerURIs} method on MqttConnectOptions.
- *
+ *
*
* The serverURI
parameter is typically used with the the clientId
parameter to form a key. The key is used to store and reference messages while they
* are being delivered. Hence the serverURI specified on the constructor must still be specified even if a list of servers is specified on an MqttConnectOptions object. The
* serverURI on the constructor must remain the same across restarts of the client for delivery of messages to be maintained from a given client to a given server or set of
* servers.
- *
+ *
*
* The address of the server to connect to is specified as a URI. Two types of connection are supported tcp://
for a TCP connection and ssl://
for a
* TCP connection secured by SSL/TLS. For example:
@@ -210,7 +213,7 @@ public MqttAsyncClient(
*
* If the port is not specified, it will default to 1883 for tcp://
" URIs, and 8883 for ssl://
URIs.
*
- *
+ *
*
* A client identifier clientId
must be specified and be less that 65535 characters. It must be unique across all clients connecting to the same server. The
* clientId is used by the server to store data related to the client, hence it is important that the clientId remain the same when connecting to a server if durable
@@ -229,7 +232,7 @@ public MqttAsyncClient(
*
SSL Properties - applications can supply SSL settings as a simple Java Properties using {@link MqttConnectOptions#setSSLProperties(Properties)}.
* Use JVM settings - There are a number of standard Java system properties that can be used to configure key and trust stores.
*
- *
+ *
*
* In Java ME, the platform settings are used for SSL connections.
*
@@ -244,7 +247,7 @@ public MqttAsyncClient(
* An implementation of file-based persistence is provided in class {@link MqttDefaultFilePersistence} which will work in all Java SE based systems. If no persistence is
* needed, the persistence parameter can be explicitly set to null
.
*
- *
+ *
* @param serverURI
* the address of the server to connect to, specified as a URI. Can be overridden using {@link MqttConnectOptions#setServerURIs(String[])}
* @param clientId
@@ -298,6 +301,7 @@ public MqttAsyncClient(
this.mqttVersion = mqttVersion;
this.persistence = persistence;
+ this.experimentsConfig = experimentsConfig;
if (this.persistence == null)
{
this.persistence = new MemoryPersistence();
@@ -331,7 +335,7 @@ protected static boolean Character_isHighSurrogate(char ch)
/**
* Factory method to create an array of network modules, one for each of the supplied URIs
- *
+ *
* @param address
* the URI for the server.
* @return a network module appropriate to the specified address.
@@ -410,29 +414,22 @@ else if (factory instanceof SSLSocketFactory)
((TCPNetworkModule) netModule).setReadTimeout(options.getReadTimeout());
break;
case MqttConnectOptions.URI_TYPE_SSL:
+ if(experimentsConfig.useNewSSLFlow()) {
+ netModule = getSSLNetworkModuleV2(address, options);
+ break;
+ }
shortAddress = address.substring(6);
host = getHostName(shortAddress);
port = getPort(shortAddress, 8883);
SSLSocketFactoryFactory factoryFactory = null;
- if (factory == null)
- {
- // try {
- factoryFactory = new SSLSocketFactoryFactory();
- Properties sslClientProps = options.getSSLProperties();
- if (null != sslClientProps)
- factoryFactory.initialize(sslClientProps, null);
- factory = factoryFactory.createSocketFactory(null);
- // }
- // catch (MqttDirectException ex) {
- // throw ExceptionHelper.createMqttException(ex.getCause());
- // }
- }
- else if ((factory instanceof SSLSocketFactory) == false)
- {
- throw ExceptionHelper.createMqttException(MqttException.REASON_CODE_SOCKET_FACTORY_MISMATCH);
+
+ factoryFactory = new SSLSocketFactoryFactory();
+ Properties sslClientProps = options.getSSLProperties();
+ if (null != sslClientProps) {
+ factoryFactory.initialize(sslClientProps, null);
}
+ factory = factoryFactory.createSocketFactory(null);
- // Create the network module...
netModule = new SSLNetworkModule((SSLSocketFactory) factory, host, port, clientId, logger, pahoEvents);
((SSLNetworkModule) netModule).setConnectTimeout(options.getConnectionTimeout());
((SSLNetworkModule) netModule).setSSLhandshakeTimeout(options.getHandshakeTimeout());
@@ -462,23 +459,22 @@ else if (factory instanceof SSLSocketFactory) {
((WebSocketNetworkModule)netModule).setReadTimeout(options.getReadTimeout());
break;
case MqttConnectOptions.URI_TYPE_WSS:
+ if(experimentsConfig.useNewSSLFlow()) {
+ netModule = getWSSNetworkModuleV2(address, options);
+ break;
+ }
shortAddress = address.substring(6);
host = getHostName(shortAddress);
port = getPort(shortAddress, 443);
SSLSocketFactoryFactory wSSFactoryFactory = null;
- if (factory == null) {
- wSSFactoryFactory = new SSLSocketFactoryFactory();
- Properties sslClientProps = options.getSSLProperties();
- if (null != sslClientProps)
- wSSFactoryFactory.initialize(sslClientProps, null);
- factory = wSSFactoryFactory.createSocketFactory(null);
+ wSSFactoryFactory = new SSLSocketFactoryFactory();
+ sslClientProps = options.getSSLProperties();
+ if (null != sslClientProps) {
+ wSSFactoryFactory.initialize(sslClientProps, null);
}
- else if ((factory instanceof SSLSocketFactory) == false) {
- throw ExceptionHelper.createMqttException(MqttException.REASON_CODE_SOCKET_FACTORY_MISMATCH);
- }
+ factory = wSSFactoryFactory.createSocketFactory(null);
- // Create the network module...
netModule = new WebSocketSecureNetworkModule((SSLSocketFactory) factory, address, host, port, clientId, logger, pahoEvents);
((WebSocketSecureNetworkModule)netModule).setConnectTimeout(options.getConnectionTimeout());
((WebSocketSecureNetworkModule)netModule).setSSLhandshakeTimeout(options.getHandshakeTimeout());
@@ -501,6 +497,56 @@ else if ((factory instanceof SSLSocketFactory) == false) {
return netModule;
}
+ private NetworkModule getSSLNetworkModuleV2(String address, MqttConnectOptions options)
+ throws MqttException {
+ String shortAddress = address.substring(6);
+ String host = getHostName(shortAddress);
+ int port = getPort(shortAddress, 443);
+
+ // Create the network module...
+ NetworkModule netModule = new SSLNetworkModuleV2(
+ options.getSocketFactory(),
+ options.getSslSocketFactory(),
+ options.getX509TrustManager(),
+ options.getConnectionSpec(),
+ options.getAlpnProtocolList(),
+ host,
+ port,
+ clientId,
+ logger,
+ pahoEvents
+ );
+ ((SSLNetworkModuleV2) netModule).setConnectTimeout(options.getConnectionTimeout());
+ ((SSLNetworkModuleV2) netModule).setSSLhandshakeTimeout(options.getHandshakeTimeout());
+ ((SSLNetworkModuleV2) netModule).setReadTimeout(options.getReadTimeout());
+ return netModule;
+ }
+
+ private NetworkModule getWSSNetworkModuleV2(String address, MqttConnectOptions options)
+ throws MqttException {
+ String shortAddress = address.substring(6);
+ String host = getHostName(shortAddress);
+ int port = getPort(shortAddress, 443);
+
+ NetworkModule netModule = new WebSocketSecureNetworkModuleV2(
+ options.getSocketFactory(),
+ options.getSslSocketFactory(),
+ options.getX509TrustManager(),
+ options.getConnectionSpec(),
+ options.getAlpnProtocolList(),
+ address,
+ host,
+ port,
+ clientId,
+ logger,
+ pahoEvents
+ );
+ ((WebSocketSecureNetworkModuleV2) netModule).setConnectTimeout(options.getConnectionTimeout());
+ ((WebSocketSecureNetworkModuleV2) netModule).setSSLhandshakeTimeout(options.getHandshakeTimeout());
+ ((WebSocketSecureNetworkModuleV2) netModule).setReadTimeout(options.getReadTimeout());
+ return netModule;
+ }
+
private int getPort(String uri, int defaultPort)
{
int port;
@@ -529,7 +575,7 @@ private String getHostName(String uri)
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#connect(java.lang.Object, org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
public IMqttToken connect(Object userContext, IMqttActionListener callback) throws MqttException, MqttSecurityException
@@ -539,7 +585,7 @@ public IMqttToken connect(Object userContext, IMqttActionListener callback) thro
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#connect()
*/
public IMqttToken connect() throws MqttException, MqttSecurityException
@@ -549,7 +595,7 @@ public IMqttToken connect() throws MqttException, MqttSecurityException
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#connect(org.eclipse.paho.client.mqttv3.MqttConnectOptions)
*/
public IMqttToken connect(MqttConnectOptions options) throws MqttException, MqttSecurityException
@@ -559,7 +605,7 @@ public IMqttToken connect(MqttConnectOptions options) throws MqttException, Mqtt
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#connect(org.eclipse.paho.client.mqttv3.MqttConnectOptions, java.lang.Object,
* org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
@@ -601,7 +647,7 @@ public IMqttToken connect(MqttConnectOptions options, Object userContext, IMqttA
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#disconnect(java.lang.Object, org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
public IMqttToken disconnect(Object userContext, IMqttActionListener callback) throws MqttException
@@ -611,7 +657,7 @@ public IMqttToken disconnect(Object userContext, IMqttActionListener callback) t
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#disconnect()
*/
public IMqttToken disconnect() throws MqttException
@@ -621,7 +667,7 @@ public IMqttToken disconnect() throws MqttException
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#disconnect(long)
*/
public IMqttToken disconnect(long quiesceTimeout) throws MqttException
@@ -631,7 +677,7 @@ public IMqttToken disconnect(long quiesceTimeout) throws MqttException
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#disconnect(long, java.lang.Object, org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
public IMqttToken disconnect(long quiesceTimeout, Object userContext, IMqttActionListener callback) throws MqttException
@@ -660,7 +706,7 @@ public IMqttToken disconnect(long quiesceTimeout, Object userContext, IMqttActio
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#disconnectForcibly()
*/
public void disconnectForcibly() throws MqttException
@@ -670,7 +716,7 @@ public void disconnectForcibly() throws MqttException
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#disconnectForcibly(long)
*/
public void disconnectForcibly(long disconnectTimeout) throws MqttException
@@ -680,7 +726,7 @@ public void disconnectForcibly(long disconnectTimeout) throws MqttException
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#disconnectForcibly(long, long)
*/
public void disconnectForcibly(long quiesceTimeout, long disconnectTimeout) throws MqttException
@@ -690,24 +736,24 @@ public void disconnectForcibly(long quiesceTimeout, long disconnectTimeout) thro
/*
* (non-Javadoc)
- *
+ *
* @see IMqttAsyncClient#isConnected()
*/
public boolean isConnected()
{
return comms.isConnected();
}
-
+
public boolean isConnecting()
{
return comms.isConnecting();
}
-
+
public boolean isDisconnecting()
{
return comms.isDisconnecting();
}
-
+
public boolean isDisconnected()
{
return comms.isDisconnected();
@@ -715,7 +761,7 @@ public boolean isDisconnected()
/*
* (non-Javadoc)
- *
+ *
* @see IMqttAsyncClient#getClientId()
*/
public String getClientId()
@@ -735,7 +781,7 @@ public void setClientId(String clientId)
/*
* (non-Javadoc)
- *
+ *
* @see IMqttAsyncClient#getServerURI()
*/
public String getServerURI()
@@ -769,7 +815,7 @@ public void setServerURI(String serverURI) throws MqttException
*
* When you build an application, the design of the topic tree should take into account the following principles of topic name syntax and semantics:
*
- *
+ *
*
* - A topic must be at least one character long.
* - Topic names are case sensitive. For example, ACCOUNTS and Accounts are two different topics.
@@ -778,17 +824,17 @@ public void setServerURI(String serverURI) throws MqttException
* - A leading "/" creates a distinct topic. For example, /finance is different from finance. /finance matches "+/+" and "/+", but not "+".
* - Do not include the null character (Unicode \x0000) in any topic.
*
- *
+ *
*
* The following principles apply to the construction and content of a topic tree:
*
- *
+ *
*
* - The length is limited to 64k but within that there are no limits to the number of levels in a topic tree.
* - There can be any number of root nodes; that is, there can be any number of topic trees.
*
*
- *
+ *
* @param topic
* the topic to use, for example "finance/stock/ibm".
* @return an MqttTopic object, which can be used to publish messages to the topic.
@@ -811,7 +857,7 @@ protected MqttTopic getTopic(String topic)
/*
* (non-Javadoc) Check and send a ping if needed. By default, client sends PingReq to server to keep the connection to server. For some platforms which cannot use this
* mechanism, such as Android, developer needs to handle the ping request manually with this method.
- *
+ *
* @throws MqttException for other errors encountered while publishing the message.
*/
public IMqttToken checkPing(Object userContext, IMqttActionListener callback) throws MqttException
@@ -831,10 +877,10 @@ public void checkActivity()
{
comms.checkActivity();
}
-
+
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#subscribe(java.lang.String, int, java.lang.Object, org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
public IMqttToken subscribe(String topicFilter, int qos, Object userContext, IMqttActionListener callback) throws MqttException
@@ -844,7 +890,7 @@ public IMqttToken subscribe(String topicFilter, int qos, Object userContext, IMq
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#subscribe(java.lang.String, int)
*/
public IMqttToken subscribe(String topicFilter, int qos) throws MqttException
@@ -854,7 +900,7 @@ public IMqttToken subscribe(String topicFilter, int qos) throws MqttException
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#subscribe(java.lang.String[], int[])
*/
public IMqttToken subscribe(String[] topicFilters, int[] qos) throws MqttException
@@ -864,7 +910,7 @@ public IMqttToken subscribe(String[] topicFilters, int[] qos) throws MqttExcepti
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#subscribe(java.lang.String[], int[], java.lang.Object, org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
public IMqttToken subscribe(String[] topicFilters, int[] qos, Object userContext, IMqttActionListener callback) throws MqttException
@@ -906,7 +952,7 @@ public IMqttToken subscribe(String[] topicFilters, int[] qos, Object userContext
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#unsubscribe(java.lang.String, java.lang.Object, org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
public IMqttToken unsubscribe(String topicFilter, Object userContext, IMqttActionListener callback) throws MqttException
@@ -916,7 +962,7 @@ public IMqttToken unsubscribe(String topicFilter, Object userContext, IMqttActio
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#unsubscribe(java.lang.String)
*/
public IMqttToken unsubscribe(String topicFilter) throws MqttException
@@ -926,7 +972,7 @@ public IMqttToken unsubscribe(String topicFilter) throws MqttException
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#unsubscribe(java.lang.String[])
*/
public IMqttToken unsubscribe(String[] topicFilters) throws MqttException
@@ -936,7 +982,7 @@ public IMqttToken unsubscribe(String[] topicFilters) throws MqttException
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#unsubscribe(java.lang.String[], java.lang.Object, org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
public IMqttToken unsubscribe(String[] topicFilters, Object userContext, IMqttActionListener callback) throws MqttException
@@ -975,7 +1021,7 @@ public IMqttToken unsubscribe(String[] topicFilters, Object userContext, IMqttAc
/*
* (non-Javadoc)
- *
+ *
* @see IMqttAsyncClient#setCallback(MqttCallback)
*/
public void setCallback(MqttCallback callback)
@@ -989,7 +1035,7 @@ public void setCallback(MqttCallback callback)
* When cleanSession is set to false, an application must ensure it uses the same client identifier when it reconnects to the server to resume state and maintain assured
* message delivery.
*
- *
+ *
* @return a generated client identifier
* @see MqttConnectOptions#setCleanSession(boolean)
*/
@@ -1001,7 +1047,7 @@ public static String generateClientId()
/*
* (non-Javadoc)
- *
+ *
* @see IMqttAsyncClient#getPendingDeliveryTokens()
*/
public IMqttDeliveryToken[] getPendingDeliveryTokens()
@@ -1011,7 +1057,7 @@ public IMqttDeliveryToken[] getPendingDeliveryTokens()
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#publish(java.lang.String, byte[], int, boolean, java.lang.Object, org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
public IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean retained, Object userContext, IMqttActionListener callback) throws MqttException,
@@ -1025,7 +1071,7 @@ public IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#publish(java.lang.String, byte[], int, boolean)
*/
public IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean retained) throws MqttException, MqttPersistenceException
@@ -1035,7 +1081,7 @@ public IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#publish(java.lang.String, org.eclipse.paho.client.mqttv3.MqttMessage)
*/
public IMqttDeliveryToken publish(String topic, MqttMessage message) throws MqttException, MqttPersistenceException
@@ -1045,7 +1091,7 @@ public IMqttDeliveryToken publish(String topic, MqttMessage message) throws Mqtt
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#publish(java.lang.String, org.eclipse.paho.client.mqttv3.MqttMessage, java.lang.Object,
* org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
@@ -1073,7 +1119,7 @@ public IMqttDeliveryToken publish(String topic, MqttMessage message, Object user
/*
* (non-Javadoc)
- *
+ *
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#close()
*/
public void close() throws MqttException
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttConnectOptions.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttConnectOptions.java
index d938c965..767a77a3 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttConnectOptions.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttConnectOptions.java
@@ -15,6 +15,7 @@
*/
package org.eclipse.paho.client.mqttv3;
+import org.eclipse.paho.client.mqttv3.internal.tls.CertificateChainCleaner;
import org.eclipse.paho.client.mqttv3.internal.wire.UserProperty;
import java.net.URI;
@@ -23,6 +24,8 @@
import java.util.Properties;
import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.X509TrustManager;
/**
* Holds the set of options that control how the client connects to a server.
@@ -78,6 +81,14 @@ public class MqttConnectOptions
private SocketFactory socketFactory;
+ private SSLSocketFactory sslSocketFactory;
+
+ private X509TrustManager x509TrustManager;
+
+ private ConnectionSpec connectionSpec;
+
+ private List alpnProtocolList;
+
private Properties sslClientProps = null;
private boolean cleanSession = CLEAN_SESSION_DEFAULT;
@@ -371,6 +382,39 @@ public void setSocketFactory(SocketFactory socketFactory)
this.socketFactory = socketFactory;
}
+ public SSLSocketFactory getSslSocketFactory() {
+ return sslSocketFactory;
+ }
+
+ public void setSslSocketFactory(SSLSocketFactory sslSocketFactory) {
+ this.sslSocketFactory = sslSocketFactory;
+ }
+
+ public X509TrustManager getX509TrustManager() {
+ return x509TrustManager;
+ }
+
+ public void setX509TrustManager(X509TrustManager x509TrustManager) {
+ this.x509TrustManager = x509TrustManager;
+ }
+
+ public ConnectionSpec getConnectionSpec() {
+ return connectionSpec;
+ }
+
+ public void setConnectionSpec(
+ ConnectionSpec connectionSpec) {
+ this.connectionSpec = connectionSpec;
+ }
+
+ public List getAlpnProtocolList() {
+ return alpnProtocolList;
+ }
+
+ public void setAlpnProtocolList(List alpnProtocolList) {
+ this.alpnProtocolList = alpnProtocolList;
+ }
+
/**
* Returns the topic to be used for last will and testament (LWT).
*
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/Protocol.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/Protocol.kt
new file mode 100644
index 00000000..d0cdc17c
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/Protocol.kt
@@ -0,0 +1,5 @@
+package org.eclipse.paho.client.mqttv3
+
+data class Protocol(
+ val name: String
+)
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/SuppressSignatureCheck.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/SuppressSignatureCheck.kt
new file mode 100644
index 00000000..1434b1f4
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/SuppressSignatureCheck.kt
@@ -0,0 +1,12 @@
+package org.eclipse.paho.client.mqttv3
+
+import java.lang.annotation.Documented
+import kotlin.annotation.AnnotationRetention.BINARY
+import kotlin.annotation.AnnotationTarget.CLASS
+import kotlin.annotation.AnnotationTarget.CONSTRUCTOR
+import kotlin.annotation.AnnotationTarget.FUNCTION
+
+@Retention(BINARY)
+@Documented
+@Target(CONSTRUCTOR, CLASS, FUNCTION)
+annotation class SuppressSignatureCheck
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/Util.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/Util.kt
new file mode 100644
index 00000000..a7c50a51
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/Util.kt
@@ -0,0 +1,68 @@
+package org.eclipse.paho.client.mqttv3
+
+internal fun readFieldOrNull(instance: Any, fieldType: Class, fieldName: String): T? {
+ var c: Class<*> = instance.javaClass
+ while (c != Any::class.java) {
+ try {
+ val field = c.getDeclaredField(fieldName)
+ field.isAccessible = true
+ val value = field.get(instance)
+ return if (!fieldType.isInstance(value)) null else fieldType.cast(value)
+ } catch (_: NoSuchFieldException) {
+ }
+
+ c = c.superclass
+ }
+
+ // Didn't find the field we wanted. As a last gasp attempt,
+ // try to find the value on a delegate.
+ if (fieldName != "delegate") {
+ val delegate = readFieldOrNull(instance, Any::class.java, "delegate")
+ if (delegate != null) return readFieldOrNull(delegate, fieldType, fieldName)
+ }
+
+ return null
+}
+
+internal fun Array.hasIntersection(
+ other: Array?,
+ comparator: Comparator
+): Boolean {
+ if (isEmpty() || other == null || other.isEmpty()) {
+ return false
+ }
+ for (a in this) {
+ for (b in other) {
+ if (comparator.compare(a, b) == 0) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+internal fun Array.intersect(
+ other: Array,
+ comparator: Comparator
+): Array {
+ val result = mutableListOf()
+ for (a in this) {
+ for (b in other) {
+ if (comparator.compare(a, b) == 0) {
+ result.add(a)
+ break
+ }
+ }
+ }
+ return result.toTypedArray()
+}
+
+internal fun Array.indexOf(value: String, comparator: Comparator): Int =
+ indexOfFirst { comparator.compare(it, value) == 0 }
+
+@Suppress("UNCHECKED_CAST")
+internal fun Array.concat(value: String): Array {
+ val result = copyOf(size + 1)
+ result[result.lastIndex] = value
+ return result as Array
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/SSLNetworkModule.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/SSLNetworkModule.java
index e1184896..0a169a41 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/SSLNetworkModule.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/SSLNetworkModule.java
@@ -3,11 +3,11 @@
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
- * and Eclipse Distribution License v1.0 which accompany this distribution.
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
*
- * The Eclipse Public License is available at
+ * The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
- * and the Eclipse Distribution License is available at
+ * and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
@@ -63,7 +63,6 @@ public void setEnabledCiphers(String[] enabledCiphers)
this.enabledCiphers = enabledCiphers;
if ((socket != null) && (enabledCiphers != null))
{
-
((SSLSocket) socket).setEnabledCipherSuites(enabledCiphers);
}
}
@@ -103,7 +102,7 @@ public void start() throws IOException, MqttException
throw ex;
}
}
-
+
public void stop() throws IOException
{
// In case of SSLSocket we should not try to shutdownOutput and shutdownInput it would result
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/SSLNetworkModuleV2.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/SSLNetworkModuleV2.java
new file mode 100644
index 00000000..1e99e08f
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/SSLNetworkModuleV2.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Dave Locke - initial API and implementation and/or initial documentation
+ */
+package org.eclipse.paho.client.mqttv3.internal;
+
+import org.eclipse.paho.client.mqttv3.ConnectionSpec;
+import org.eclipse.paho.client.mqttv3.ILogger;
+import org.eclipse.paho.client.mqttv3.IPahoEvents;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.Protocol;
+import org.eclipse.paho.client.mqttv3.internal.platform.Platform;
+import org.eclipse.paho.client.mqttv3.internal.tls.CertificateChainCleaner;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.X509TrustManager;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A network module for connecting over SSL.
+ */
+public class SSLNetworkModuleV2 extends TCPNetworkModule {
+ private SocketFactory socketFactory;
+ private SSLSocketFactory sslSocketFactory;
+ private X509TrustManager x509TrustManager;
+ private ConnectionSpec connectionSpec;
+ private List alpnProtocolList;
+
+ private int handshakeTimeoutSecs;
+
+ final static String className = SSLNetworkModuleV2.class.getName();
+
+ private final String TAG = "SSLNETWORKMODULE";
+
+ /**
+ * Constructs a new SSLNetworkModule using the specified host and port. The supplied
+ * SSLSocketFactory is used to supply the network socket.
+ */
+
+ public SSLNetworkModuleV2(
+ SocketFactory socketFactory,
+ SSLSocketFactory sslSocketFactory,
+ X509TrustManager x509TrustManager,
+ ConnectionSpec connectionSpec,
+ List alpnProtocolList,
+ String host,
+ int port,
+ String resourceContext,
+ ILogger logger,
+ IPahoEvents pahoEvents
+ ) {
+ super(socketFactory, host, port, resourceContext, logger, pahoEvents);
+ this.socketFactory = socketFactory;
+ this.sslSocketFactory = sslSocketFactory;
+ this.x509TrustManager = x509TrustManager;
+ this.connectionSpec = connectionSpec;
+ this.alpnProtocolList = alpnProtocolList;
+ }
+
+ public void setSSLhandshakeTimeout(int timeout) {
+ this.handshakeTimeoutSecs = timeout;
+ }
+
+ public void start() throws IOException, MqttException {
+ super.start();
+ long socketStartTime = System.nanoTime();
+ try {
+ pahoEvents.onSSLSocketAttempt(port, host, socket.getSoTimeout());
+
+ socket = sslSocketFactory.createSocket(socket, host, port, true);
+
+ connectionSpec.apply((SSLSocket) socket, false);
+ if (connectionSpec.supportsTlsExtensions()) {
+ Platform.get().configureTlsExtensions((SSLSocket) socket, host, alpnProtocolList);
+ }
+ long socketEndTime = System.nanoTime();
+ pahoEvents.onSSLSocketSuccess(port, host, socket.getSoTimeout(),
+ TimeUnit.NANOSECONDS.toMillis(socketEndTime - socketStartTime));
+
+ int soTimeout = socket.getSoTimeout();
+ // RTC 765: Set a timeout to avoid the SSL handshake being blocked indefinitely
+ socket.setSoTimeout(this.handshakeTimeoutSecs * 1000);
+ long handshakeStartTime = System.nanoTime();
+ ((SSLSocket) socket).startHandshake();
+ long handshakeEndTime = System.nanoTime();
+
+ pahoEvents.onSSLHandshakeSuccess(port, host, socket.getSoTimeout(),
+ TimeUnit.NANOSECONDS.toMillis(handshakeEndTime - handshakeStartTime));
+
+ // reset timeout to default value
+ socket.setSoTimeout(soTimeout);
+ } catch (IOException ex) {
+ long socketEndTime = System.nanoTime();
+ pahoEvents.onSSLSocketFailure(port, host, socket.getSoTimeout(), ex,
+ TimeUnit.NANOSECONDS.toMillis(socketEndTime - socketStartTime));
+ throw ex;
+ }
+ }
+
+ public void stop() throws IOException {
+ // In case of SSLSocket we should not try to shutdownOutput and shutdownInput it would result
+ // in java.lang.UnsupportedOperationException. only SSLSocket.close() is enough to close
+ // an SSLSocket.
+ socket.close();
+ }
+}
\ No newline at end of file
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Android10Platform.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Android10Platform.kt
new file mode 100644
index 00000000..14b636e6
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Android10Platform.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.security.NetworkSecurityPolicy
+import android.util.CloseGuard
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+import org.eclipse.paho.client.mqttv3.Protocol
+import org.eclipse.paho.client.mqttv3.SuppressSignatureCheck
+import org.eclipse.paho.client.mqttv3.internal.platform.android.Android10SocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.platform.android.AndroidCertificateChainCleaner
+import org.eclipse.paho.client.mqttv3.internal.platform.android.AndroidSocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.platform.android.BouncyCastleSocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.platform.android.ConscryptSocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.platform.android.DeferredSocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.tls.CertificateChainCleaner
+
+/** Android 29+. */
+@SuppressSignatureCheck
+class Android10Platform : Platform() {
+ private val socketAdapters = listOfNotNull(
+ Android10SocketAdapter.buildIfSupported(),
+ DeferredSocketAdapter(AndroidSocketAdapter.playProviderFactory),
+ // Delay and Defer any initialisation of Conscrypt and BouncyCastle
+ DeferredSocketAdapter(ConscryptSocketAdapter.factory),
+ DeferredSocketAdapter(BouncyCastleSocketAdapter.factory)
+ ).filter { it.isSupported() }
+
+ override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? =
+ socketAdapters.find { it.matchesSocketFactory(sslSocketFactory) }
+ ?.trustManager(sslSocketFactory)
+
+ override fun configureTlsExtensions(sslSocket: SSLSocket, hostname: String?, protocols: List) {
+ // No TLS extensions if the socket class is custom.
+ socketAdapters.find { it.matchesSocket(sslSocket) }
+ ?.configureTlsExtensions(sslSocket, hostname, protocols)
+ }
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? =
+ // No TLS extensions if the socket class is custom.
+ socketAdapters.find { it.matchesSocket(sslSocket) }?.getSelectedProtocol(sslSocket)
+
+ override fun getStackTraceForCloseable(closer: String): Any? {
+ return if (Build.VERSION.SDK_INT >= 30) {
+ CloseGuard().apply { open(closer) }
+ } else {
+ super.getStackTraceForCloseable(closer)
+ }
+ }
+
+ override fun logCloseableLeak(message: String, stackTrace: Any?) {
+ if (Build.VERSION.SDK_INT >= 30) {
+ (stackTrace as CloseGuard).warnIfOpen()
+ } else {
+ // Unable to report via CloseGuard. As a last-ditch effort, send it to the logger.
+ super.logCloseableLeak(message, stackTrace)
+ }
+ }
+
+ @SuppressLint("NewApi")
+ override fun isCleartextTrafficPermitted(hostname: String): Boolean =
+ NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted(hostname)
+
+ override fun buildCertificateChainCleaner(trustManager: X509TrustManager): CertificateChainCleaner =
+ AndroidCertificateChainCleaner.buildIfSupported(trustManager) ?: super.buildCertificateChainCleaner(trustManager)
+
+ companion object {
+ val isSupported: Boolean = isAndroid && Build.VERSION.SDK_INT >= 29
+
+ fun buildIfSupported(): Platform? = if (isSupported) Android10Platform() else null
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/AndroidPlatform.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/AndroidPlatform.kt
new file mode 100644
index 00000000..c0ef8bd1
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/AndroidPlatform.kt
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2016 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform
+
+import android.os.Build
+import android.security.NetworkSecurityPolicy
+import java.io.IOException
+import java.lang.reflect.InvocationTargetException
+import java.lang.reflect.Method
+import java.net.InetSocketAddress
+import java.net.Socket
+import java.security.cert.TrustAnchor
+import java.security.cert.X509Certificate
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+import org.eclipse.paho.client.mqttv3.Protocol
+import org.eclipse.paho.client.mqttv3.SuppressSignatureCheck
+import org.eclipse.paho.client.mqttv3.internal.platform.android.AndroidCertificateChainCleaner
+import org.eclipse.paho.client.mqttv3.internal.platform.android.AndroidSocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.platform.android.BouncyCastleSocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.platform.android.ConscryptSocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.platform.android.DeferredSocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.platform.android.StandardAndroidSocketAdapter
+import org.eclipse.paho.client.mqttv3.internal.tls.CertificateChainCleaner
+import org.eclipse.paho.client.mqttv3.internal.tls.TrustRootIndex
+
+/** Android 5+. */
+@SuppressSignatureCheck
+class AndroidPlatform : Platform() {
+ private val socketAdapters = listOfNotNull(
+ StandardAndroidSocketAdapter.buildIfSupported(),
+ DeferredSocketAdapter(AndroidSocketAdapter.playProviderFactory),
+ // Delay and Defer any initialisation of Conscrypt and BouncyCastle
+ DeferredSocketAdapter(ConscryptSocketAdapter.factory),
+ DeferredSocketAdapter(BouncyCastleSocketAdapter.factory)
+ ).filter { it.isSupported() }
+
+ @Throws(IOException::class)
+ override fun connectSocket(
+ socket: Socket,
+ address: InetSocketAddress,
+ connectTimeout: Int
+ ) {
+ try {
+ socket.connect(address, connectTimeout)
+ } catch (e: ClassCastException) {
+ // On android 8.0, socket.connect throws a ClassCastException due to a bug
+ // see https://issuetracker.google.com/issues/63649622
+ if (Build.VERSION.SDK_INT == 26) {
+ throw IOException("Exception in connect", e)
+ } else {
+ throw e
+ }
+ }
+ }
+
+ override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? =
+ socketAdapters.find { it.matchesSocketFactory(sslSocketFactory) }
+ ?.trustManager(sslSocketFactory)
+
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List<@JvmSuppressWildcards Protocol>
+ ) {
+ // No TLS extensions if the socket class is custom.
+ socketAdapters.find { it.matchesSocket(sslSocket) }
+ ?.configureTlsExtensions(sslSocket, hostname, protocols)
+ }
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? =
+ // No TLS extensions if the socket class is custom.
+ socketAdapters.find { it.matchesSocket(sslSocket) }?.getSelectedProtocol(sslSocket)
+
+ override fun isCleartextTrafficPermitted(hostname: String): Boolean = when {
+ Build.VERSION.SDK_INT >= 24 -> NetworkSecurityPolicy.getInstance()
+ .isCleartextTrafficPermitted(hostname)
+ Build.VERSION.SDK_INT >= 23 -> NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted
+ else -> true
+ }
+
+ override fun buildCertificateChainCleaner(trustManager: X509TrustManager): CertificateChainCleaner =
+ AndroidCertificateChainCleaner.buildIfSupported(trustManager)
+ ?: super.buildCertificateChainCleaner(trustManager)
+
+ override fun buildTrustRootIndex(trustManager: X509TrustManager): TrustRootIndex = try {
+ // From org.conscrypt.TrustManagerImpl, we want the method with this signature:
+ // private TrustAnchor findTrustAnchorByIssuerAndSignature(X509Certificate lastCert);
+ val method = trustManager.javaClass.getDeclaredMethod(
+ "findTrustAnchorByIssuerAndSignature",
+ X509Certificate::class.java
+ )
+ method.isAccessible = true
+ CustomTrustRootIndex(trustManager, method)
+ } catch (e: NoSuchMethodException) {
+ super.buildTrustRootIndex(trustManager)
+ }
+
+ /**
+ * A trust manager for Android applications that customize the trust manager.
+ *
+ * This class exploits knowledge of Android implementation details. This class is potentially
+ * much faster to initialize than [BasicTrustRootIndex] because it doesn't need to load and
+ * index trusted CA certificates.
+ */
+ internal data class CustomTrustRootIndex(
+ private val trustManager: X509TrustManager,
+ private val findByIssuerAndSignatureMethod: Method
+ ) : TrustRootIndex {
+ override fun findByIssuerAndSignature(cert: X509Certificate): X509Certificate? {
+ return try {
+ val trustAnchor = findByIssuerAndSignatureMethod.invoke(
+ trustManager,
+ cert
+ ) as TrustAnchor
+ trustAnchor.trustedCert
+ } catch (e: IllegalAccessException) {
+ throw AssertionError("unable to get issues and signature", e)
+ } catch (_: InvocationTargetException) {
+ null
+ }
+ }
+ }
+
+ companion object {
+ val isSupported: Boolean = when {
+ !isAndroid -> false
+ Build.VERSION.SDK_INT >= 30 -> false // graylisted methods are banned
+ else -> {
+ // Fail Fast
+ check(
+ Build.VERSION.SDK_INT >= 21
+ ) { "Expected Android API level 21+ but was ${Build.VERSION.SDK_INT}" }
+
+ true
+ }
+ }
+
+ fun buildIfSupported(): Platform? = if (isSupported) AndroidPlatform() else null
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/BouncyCastlePlatform.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/BouncyCastlePlatform.kt
new file mode 100644
index 00000000..81cf7108
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/BouncyCastlePlatform.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform
+
+import java.security.KeyStore
+import java.security.Provider
+import javax.net.ssl.SSLContext
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.TrustManagerFactory
+import javax.net.ssl.X509TrustManager
+import org.bouncycastle.jsse.BCSSLSocket
+import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
+import org.eclipse.paho.client.mqttv3.Protocol
+
+/**
+ * Platform using BouncyCastle if installed as the first Security Provider.
+ *
+ * Requires org.bouncycastle:bctls-jdk15on on the classpath.
+ */
+class BouncyCastlePlatform private constructor() : Platform() {
+ private val provider: Provider = BouncyCastleJsseProvider()
+
+ override fun newSSLContext(): SSLContext =
+ SSLContext.getInstance("TLS", provider)
+
+ override fun platformTrustManager(): X509TrustManager {
+ val factory = TrustManagerFactory.getInstance(
+ "PKIX",
+ BouncyCastleJsseProvider.PROVIDER_NAME
+ )
+ factory.init(null as KeyStore?)
+ val trustManagers = factory.trustManagers!!
+ check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) {
+ "Unexpected default trust managers: ${trustManagers.contentToString()}"
+ }
+ return trustManagers[0] as X509TrustManager
+ }
+
+ override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager =
+ throw UnsupportedOperationException(
+ "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported with BouncyCastle"
+ )
+
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List<@JvmSuppressWildcards Protocol>
+ ) {
+ if (sslSocket is BCSSLSocket) {
+ val sslParameters = sslSocket.parameters
+
+ // Enable ALPN.
+ val names = alpnProtocolNames(protocols)
+ sslParameters.applicationProtocols = names.toTypedArray()
+
+ sslSocket.parameters = sslParameters
+ } else {
+ super.configureTlsExtensions(sslSocket, hostname, protocols)
+ }
+ }
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? =
+ if (sslSocket is BCSSLSocket) {
+ when (val protocol = (sslSocket as BCSSLSocket).applicationProtocol) {
+ // Handles both un-configured and none selected.
+ null, "" -> null
+ else -> protocol
+ }
+ } else {
+ super.getSelectedProtocol(sslSocket)
+ }
+
+ companion object {
+ val isSupported: Boolean = try {
+ // Trigger an early exception over a fatal error, prefer a RuntimeException over Error.
+ Class.forName(
+ "org.bouncycastle.jsse.provider.BouncyCastleJsseProvider",
+ false,
+ javaClass.classLoader
+ )
+
+ true
+ } catch (_: ClassNotFoundException) {
+ false
+ }
+
+ fun buildIfSupported(): BouncyCastlePlatform? =
+ if (isSupported) BouncyCastlePlatform() else null
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/ConscryptPlatform.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/ConscryptPlatform.kt
new file mode 100644
index 00000000..2d2ff6ab
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/ConscryptPlatform.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2014 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform
+
+import java.security.KeyStore
+import java.security.Provider
+import java.security.cert.X509Certificate
+import javax.net.ssl.SSLContext
+import javax.net.ssl.SSLSession
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.TrustManager
+import javax.net.ssl.TrustManagerFactory
+import javax.net.ssl.X509TrustManager
+import org.conscrypt.Conscrypt
+import org.conscrypt.ConscryptHostnameVerifier
+import org.eclipse.paho.client.mqttv3.Protocol
+
+/**
+ * Platform using Conscrypt (conscrypt.org) if installed as the first Security Provider.
+ *
+ * Requires org.conscrypt:conscrypt-openjdk-uber >= 2.1.0 on the classpath.
+ */
+class ConscryptPlatform private constructor() : Platform() {
+ private val provider: Provider = Conscrypt.newProvider()
+
+ // See release notes https://groups.google.com/forum/#!forum/conscrypt
+ // for version differences
+ override fun newSSLContext(): SSLContext =
+ // supports TLSv1.3 by default (version api is >= 1.4.0)
+ SSLContext.getInstance("TLS", provider)
+
+ override fun platformTrustManager(): X509TrustManager {
+ val trustManagers = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).apply {
+ init(null as KeyStore?)
+ }.trustManagers!!
+ check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) {
+ "Unexpected default trust managers: ${trustManagers.contentToString()}"
+ }
+ val x509TrustManager = trustManagers[0] as X509TrustManager
+ // Disabled because OkHttp will run anyway
+ Conscrypt.setHostnameVerifier(x509TrustManager, DisabledHostnameVerifier)
+ return x509TrustManager
+ }
+
+ internal object DisabledHostnameVerifier : ConscryptHostnameVerifier {
+ fun verify(
+ hostname: String?,
+ session: SSLSession?
+ ): Boolean {
+ return true
+ }
+
+ override fun verify(
+ certs: Array?,
+ hostname: String?,
+ session: SSLSession?
+ ): Boolean {
+ return true
+ }
+ }
+
+ override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? = null
+
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List<@JvmSuppressWildcards Protocol>
+ ) {
+ if (Conscrypt.isConscrypt(sslSocket)) {
+ // Enable session tickets.
+ Conscrypt.setUseSessionTickets(sslSocket, true)
+
+ // Enable ALPN.
+ val names = alpnProtocolNames(protocols)
+ Conscrypt.setApplicationProtocols(sslSocket, names.toTypedArray())
+ } else {
+ super.configureTlsExtensions(sslSocket, hostname, protocols)
+ }
+ }
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? =
+ if (Conscrypt.isConscrypt(sslSocket)) {
+ Conscrypt.getApplicationProtocol(sslSocket)
+ } else {
+ super.getSelectedProtocol(sslSocket)
+ }
+
+ override fun newSslSocketFactory(trustManager: X509TrustManager): SSLSocketFactory {
+ return newSSLContext().apply {
+ init(null, arrayOf(trustManager), null)
+ }.socketFactory
+ }
+
+ companion object {
+ val isSupported: Boolean = try {
+ // Trigger an early exception over a fatal error, prefer a RuntimeException over Error.
+ Class.forName("org.conscrypt.Conscrypt\$Version", false, javaClass.classLoader)
+
+ when {
+ // Bump this version if we ever have a binary incompatibility
+ Conscrypt.isAvailable() && atLeastVersion(2, 1, 0) -> true
+ else -> false
+ }
+ } catch (e: NoClassDefFoundError) {
+ false
+ } catch (e: ClassNotFoundException) {
+ false
+ }
+
+ fun buildIfSupported(): ConscryptPlatform? = if (isSupported) ConscryptPlatform() else null
+
+ fun atLeastVersion(major: Int, minor: Int = 0, patch: Int = 0): Boolean {
+ val conscryptVersion = Conscrypt.version() ?: return false
+
+ if (conscryptVersion.major() != major) {
+ return conscryptVersion.major() > major
+ }
+
+ if (conscryptVersion.minor() != minor) {
+ return conscryptVersion.minor() > minor
+ }
+
+ return conscryptVersion.patch() >= patch
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Jdk8WithJettyBootPlatform.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Jdk8WithJettyBootPlatform.kt
new file mode 100644
index 00000000..62f0cc2a
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Jdk8WithJettyBootPlatform.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform
+
+import java.lang.reflect.InvocationHandler
+import java.lang.reflect.InvocationTargetException
+import java.lang.reflect.Method
+import java.lang.reflect.Proxy
+import javax.net.ssl.SSLSocket
+import org.eclipse.paho.client.mqttv3.Protocol
+
+/** OpenJDK 8 with `org.mortbay.jetty.alpn:alpn-boot` in the boot class path. */
+class Jdk8WithJettyBootPlatform(
+ private val putMethod: Method,
+ private val getMethod: Method,
+ private val removeMethod: Method,
+ private val clientProviderClass: Class<*>,
+ private val serverProviderClass: Class<*>
+) : Platform() {
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List
+ ) {
+ val names = alpnProtocolNames(protocols)
+
+ try {
+ val alpnProvider = Proxy.newProxyInstance(
+ Platform::class.java.classLoader,
+ arrayOf(clientProviderClass, serverProviderClass),
+ AlpnProvider(names)
+ )
+ putMethod.invoke(null, sslSocket, alpnProvider)
+ } catch (e: InvocationTargetException) {
+ throw AssertionError("failed to set ALPN", e)
+ } catch (e: IllegalAccessException) {
+ throw AssertionError("failed to set ALPN", e)
+ }
+ }
+
+ override fun afterHandshake(sslSocket: SSLSocket) {
+ try {
+ removeMethod.invoke(null, sslSocket)
+ } catch (e: IllegalAccessException) {
+ throw AssertionError("failed to remove ALPN", e)
+ } catch (e: InvocationTargetException) {
+ throw AssertionError("failed to remove ALPN", e)
+ }
+ }
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? {
+ try {
+ val provider =
+ Proxy.getInvocationHandler(getMethod.invoke(null, sslSocket)) as AlpnProvider
+ if (!provider.unsupported && provider.selected == null) {
+ log("ALPN callback dropped: HTTP/2 is disabled. " + "Is alpn-boot on the boot class path?")
+ return null
+ }
+ return if (provider.unsupported) null else provider.selected
+ } catch (e: InvocationTargetException) {
+ throw AssertionError("failed to get ALPN selected protocol", e)
+ } catch (e: IllegalAccessException) {
+ throw AssertionError("failed to get ALPN selected protocol", e)
+ }
+ }
+
+ /**
+ * Handle the methods of ALPN's ClientProvider and ServerProvider without a compile-time
+ * dependency on those interfaces.
+ */
+ private class AlpnProvider(
+ /** This peer's supported protocols. */
+ private val protocols: List
+ ) : InvocationHandler {
+ /** Set when remote peer notifies ALPN is unsupported. */
+ var unsupported: Boolean = false
+
+ /** The protocol the server selected. */
+ var selected: String? = null
+
+ @Throws(Throwable::class)
+ override fun invoke(proxy: Any, method: Method, args: Array?): Any? {
+ val callArgs = args ?: arrayOf()
+ val methodName = method.name
+ val returnType = method.returnType
+ if (methodName == "supports" && Boolean::class.javaPrimitiveType == returnType) {
+ return true // ALPN is supported.
+ } else if (methodName == "unsupported" && Void.TYPE == returnType) {
+ this.unsupported = true // Peer doesn't support ALPN.
+ return null
+ } else if (methodName == "protocols" && callArgs.isEmpty()) {
+ return protocols // Client advertises these protocols.
+ } else if ((methodName == "selectProtocol" || methodName == "select") &&
+ String::class.java == returnType && callArgs.size == 1 && callArgs[0] is List<*>
+ ) {
+ val peerProtocols = callArgs[0] as List<*>
+ // Pick the first known protocol the peer advertises.
+ for (i in 0..peerProtocols.size) {
+ val protocol = peerProtocols[i] as String
+ if (protocol in protocols) {
+ selected = protocol
+ return selected
+ }
+ }
+ selected = protocols[0] // On no intersection, try peer's first protocol.
+ return selected
+ } else if ((methodName == "protocolSelected" || methodName == "selected") && callArgs.size == 1) {
+ this.selected = callArgs[0] as String // Server selected this protocol.
+ return null
+ } else {
+ return method.invoke(this, *callArgs)
+ }
+ }
+ }
+
+ companion object {
+ fun buildIfSupported(): Platform? {
+ val jvmVersion = System.getProperty("java.specification.version", "unknown")
+ try {
+ // 1.8, 9, 10, 11, 12 etc
+ val version = jvmVersion.toInt()
+ if (version >= 9) return null
+ } catch (_: NumberFormatException) {
+ // expected on >= JDK 9
+ }
+
+ // Find Jetty's ALPN extension for OpenJDK.
+ try {
+ val alpnClassName = "org.eclipse.jetty.alpn.ALPN"
+ val alpnClass = Class.forName(alpnClassName, true, null)
+ val providerClass = Class.forName("$alpnClassName\$Provider", true, null)
+ val clientProviderClass =
+ Class.forName("$alpnClassName\$ClientProvider", true, null)
+ val serverProviderClass =
+ Class.forName("$alpnClassName\$ServerProvider", true, null)
+ val putMethod = alpnClass.getMethod("put", SSLSocket::class.java, providerClass)
+ val getMethod = alpnClass.getMethod("get", SSLSocket::class.java)
+ val removeMethod = alpnClass.getMethod("remove", SSLSocket::class.java)
+ return Jdk8WithJettyBootPlatform(
+ putMethod,
+ getMethod,
+ removeMethod,
+ clientProviderClass,
+ serverProviderClass
+ )
+ } catch (_: ClassNotFoundException) {
+ } catch (_: NoSuchMethodException) {
+ }
+
+ return null
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Jdk9Platform.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Jdk9Platform.kt
new file mode 100644
index 00000000..c0285867
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Jdk9Platform.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2016 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform
+
+import java.security.NoSuchAlgorithmException
+import javax.net.ssl.SSLContext
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+import org.eclipse.paho.client.mqttv3.Protocol
+import org.eclipse.paho.client.mqttv3.SuppressSignatureCheck
+
+/** OpenJDK 9+. */
+open class Jdk9Platform : Platform() {
+ @SuppressSignatureCheck
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List<@JvmSuppressWildcards Protocol>
+ ) {
+ val sslParameters = sslSocket.sslParameters
+
+ val names = alpnProtocolNames(protocols)
+
+ sslParameters.applicationProtocols = names.toTypedArray()
+
+ sslSocket.sslParameters = sslParameters
+ }
+
+ @SuppressSignatureCheck
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? {
+ return try {
+ // SSLSocket.getApplicationProtocol returns "" if application protocols values will not
+ // be used. Observed if you didn't specify SSLParameters.setApplicationProtocols
+ when (val protocol = sslSocket.applicationProtocol) {
+ null, "" -> null
+ else -> protocol
+ }
+ } catch (e: UnsupportedOperationException) {
+ // https://docs.oracle.com/javase/9/docs/api/javax/net/ssl/SSLSocket.html#getApplicationProtocol--
+ null
+ }
+ }
+
+ override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? {
+ // Not supported due to access checks on JDK 9+:
+ // java.lang.reflect.InaccessibleObjectException: Unable to make member of class
+ // sun.security.ssl.SSLSocketFactoryImpl accessible: module java.base does not export
+ // sun.security.ssl to unnamed module @xxx
+ throw UnsupportedOperationException(
+ "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported on JDK 8 (>= 252) or JDK 9+"
+ )
+ }
+
+ override fun newSSLContext(): SSLContext {
+ return when {
+ majorVersion != null && majorVersion >= 9 ->
+ SSLContext.getInstance("TLS")
+ else ->
+ try {
+ // Based on SSLSocket.getApplicationProtocol check we should
+ // have TLSv1.3 if we request it.
+ // See https://www.oracle.com/java/technologies/javase/8u261-relnotes.html
+ SSLContext.getInstance("TLSv1.3")
+ } catch (nsae: NoSuchAlgorithmException) {
+ SSLContext.getInstance("TLS")
+ }
+ }
+ }
+
+ companion object {
+ val isAvailable: Boolean
+
+ val majorVersion = System.getProperty("java.specification.version")?.toIntOrNull()
+
+ init {
+ isAvailable = if (majorVersion != null) {
+ majorVersion >= 9
+ } else {
+ try {
+ // also present on JDK8 after build 252.
+ SSLSocket::class.java.getMethod("getApplicationProtocol")
+ true
+ } catch (nsme: NoSuchMethodException) {
+ false
+ }
+ }
+ }
+
+ fun buildIfSupported(): Jdk9Platform? = if (isAvailable) Jdk9Platform() else null
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/OpenJSSEPlatform.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/OpenJSSEPlatform.kt
new file mode 100644
index 00000000..718ca797
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/OpenJSSEPlatform.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform
+
+import java.security.KeyStore
+import java.security.Provider
+import javax.net.ssl.SSLContext
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.TrustManagerFactory
+import javax.net.ssl.X509TrustManager
+import org.eclipse.paho.client.mqttv3.Protocol
+
+/**
+ * Platform using OpenJSSE (https://github.com/openjsse/openjsse) if installed as the first
+ * Security Provider.
+ *
+ * Requires org.openjsse:openjsse >= 1.1.0 on the classpath.
+ */
+class OpenJSSEPlatform private constructor() : Platform() {
+ private val provider: Provider = org.openjsse.net.ssl.OpenJSSE()
+
+ // Selects TLSv1.3 so we are specific about our intended version ranges (not just 1.3)
+ // and because it's a common pattern for VMs to have differences between supported and
+ // defaulted versions for TLS based on what is requested.
+ override fun newSSLContext(): SSLContext =
+ SSLContext.getInstance("TLSv1.3", provider)
+
+ override fun platformTrustManager(): X509TrustManager {
+ val factory = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm(),
+ provider
+ )
+ factory.init(null as KeyStore?)
+ val trustManagers = factory.trustManagers!!
+ check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) {
+ "Unexpected default trust managers: ${trustManagers.contentToString()}"
+ }
+ return trustManagers[0] as X509TrustManager
+ }
+
+ override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager =
+ throw UnsupportedOperationException(
+ "clientBuilder.sslSocketFactory(SSLSocketFactory) not supported with OpenJSSE"
+ )
+
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List<@JvmSuppressWildcards Protocol>
+ ) {
+ if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) {
+ val sslParameters = sslSocket.sslParameters
+
+ if (sslParameters is org.openjsse.javax.net.ssl.SSLParameters) {
+ // Enable ALPN.
+ val names = alpnProtocolNames(protocols)
+ sslParameters.applicationProtocols = names.toTypedArray()
+
+ sslSocket.sslParameters = sslParameters
+ }
+ } else {
+ super.configureTlsExtensions(sslSocket, hostname, protocols)
+ }
+ }
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? =
+ if (sslSocket is org.openjsse.javax.net.ssl.SSLSocket) {
+ when (val protocol = sslSocket.applicationProtocol) {
+ // Handles both un-configured and none selected.
+ null, "" -> null
+ else -> protocol
+ }
+ } else {
+ super.getSelectedProtocol(sslSocket)
+ }
+
+ companion object {
+ val isSupported: Boolean = try {
+ // Trigger an early exception over a fatal error, prefer a RuntimeException over Error.
+ Class.forName("org.openjsse.net.ssl.OpenJSSE", false, javaClass.classLoader)
+
+ true
+ } catch (_: ClassNotFoundException) {
+ false
+ }
+
+ fun buildIfSupported(): OpenJSSEPlatform? = if (isSupported) OpenJSSEPlatform() else null
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Platform.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Platform.kt
new file mode 100644
index 00000000..59064f06
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/Platform.kt
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2012 Square, Inc.
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform
+
+import java.io.IOException
+import java.net.InetSocketAddress
+import java.net.Socket
+import java.security.GeneralSecurityException
+import java.security.KeyStore
+import java.security.Security
+import java.util.logging.Level
+import java.util.logging.Logger
+import javax.net.ssl.SSLContext
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.TrustManager
+import javax.net.ssl.TrustManagerFactory
+import javax.net.ssl.X509TrustManager
+import okio.Buffer
+import org.eclipse.paho.client.mqttv3.Protocol
+import org.eclipse.paho.client.mqttv3.internal.tls.BasicCertificateChainCleaner
+import org.eclipse.paho.client.mqttv3.internal.tls.BasicTrustRootIndex
+import org.eclipse.paho.client.mqttv3.internal.tls.CertificateChainCleaner
+import org.eclipse.paho.client.mqttv3.internal.tls.TrustRootIndex
+import org.eclipse.paho.client.mqttv3.readFieldOrNull
+
+/**
+ * Access to platform-specific features.
+ *
+ * ### Session Tickets
+ *
+ * Supported on Android 2.3+.
+ * Supported on JDK 8+ via Conscrypt.
+ *
+ * ### ALPN (Application Layer Protocol Negotiation)
+ *
+ * Supported on Android 5.0+.
+ *
+ * Supported on OpenJDK 8 via the JettyALPN-boot library or Conscrypt.
+ *
+ * Supported on OpenJDK 9+ via SSLParameters and SSLSocket features.
+ *
+ * ### Trust Manager Extraction
+ *
+ * Supported on Android 2.3+ and OpenJDK 7+. There are no public APIs to recover the trust
+ * manager that was used to create an [SSLSocketFactory].
+ *
+ * Not supported by choice on JDK9+ due to access checks.
+ *
+ * ### Android Cleartext Permit Detection
+ *
+ * Supported on Android 6.0+ via `NetworkSecurityPolicy`.
+ */
+open class Platform {
+
+ /** Prefix used on custom headers. */
+ fun getPrefix() = "OkHttp"
+
+ open fun newSSLContext(): SSLContext = SSLContext.getInstance("TLS")
+
+ open fun platformTrustManager(): X509TrustManager {
+ val factory = TrustManagerFactory.getInstance(
+ TrustManagerFactory.getDefaultAlgorithm()
+ )
+ factory.init(null as KeyStore?)
+ val trustManagers = factory.trustManagers!!
+ check(trustManagers.size == 1 && trustManagers[0] is X509TrustManager) {
+ "Unexpected default trust managers: ${trustManagers.contentToString()}"
+ }
+ return trustManagers[0] as X509TrustManager
+ }
+
+ open fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? {
+ return try {
+ // Attempt to get the trust manager from an OpenJDK socket factory. We attempt this on all
+ // platforms in order to support Robolectric, which mixes classes from both Android and the
+ // Oracle JDK. Note that we don't support HTTP/2 or other nice features on Robolectric.
+ val sslContextClass = Class.forName("sun.security.ssl.SSLContextImpl")
+ val context =
+ readFieldOrNull(sslSocketFactory, sslContextClass, "context") ?: return null
+ readFieldOrNull(context, X509TrustManager::class.java, "trustManager")
+ } catch (e: ClassNotFoundException) {
+ null
+ } catch (e: RuntimeException) {
+ // Throws InaccessibleObjectException (added in JDK9) on JDK 17 due to
+ // JEP 403 Strongly Encapsulate JDK Internals.
+ if (e.javaClass.name != "java.lang.reflect.InaccessibleObjectException") {
+ throw e
+ }
+
+ null
+ }
+ }
+
+ /**
+ * Configure TLS extensions on `sslSocket` for `route`.
+ */
+ open fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List<@JvmSuppressWildcards Protocol>
+ ) {
+ }
+
+ /** Called after the TLS handshake to release resources allocated by [configureTlsExtensions]. */
+ open fun afterHandshake(sslSocket: SSLSocket) {
+ }
+
+ /** Returns the negotiated protocol, or null if no protocol was negotiated. */
+ open fun getSelectedProtocol(sslSocket: SSLSocket): String? = null
+
+ @Throws(IOException::class)
+ open fun connectSocket(socket: Socket, address: InetSocketAddress, connectTimeout: Int) {
+ socket.connect(address, connectTimeout)
+ }
+
+ open fun log(message: String, level: Int = INFO, t: Throwable? = null) {
+ val logLevel = if (level == WARN) Level.WARNING else Level.INFO
+ logger.log(logLevel, message, t)
+ }
+
+ open fun isCleartextTrafficPermitted(hostname: String): Boolean = true
+
+ /**
+ * Returns an object that holds a stack trace created at the moment this method is executed. This
+ * should be used specifically for [java.io.Closeable] objects and in conjunction with
+ * [logCloseableLeak].
+ */
+ open fun getStackTraceForCloseable(closer: String): Any? {
+ return when {
+ logger.isLoggable(Level.FINE) -> Throwable(closer) // These are expensive to allocate.
+ else -> null
+ }
+ }
+
+ open fun logCloseableLeak(message: String, stackTrace: Any?) {
+ var logMessage = message
+ if (stackTrace == null) {
+ logMessage += " To see where this was allocated, set the OkHttpClient logger level to " +
+ "FINE: Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);"
+ }
+ log(logMessage, WARN, stackTrace as Throwable?)
+ }
+
+ open fun buildCertificateChainCleaner(trustManager: X509TrustManager): CertificateChainCleaner =
+ BasicCertificateChainCleaner(buildTrustRootIndex(trustManager))
+
+ open fun buildTrustRootIndex(trustManager: X509TrustManager): TrustRootIndex =
+ BasicTrustRootIndex(*trustManager.acceptedIssuers)
+
+ open fun newSslSocketFactory(trustManager: X509TrustManager): SSLSocketFactory {
+ try {
+ return newSSLContext().apply {
+ init(null, arrayOf(trustManager), null)
+ }.socketFactory
+ } catch (e: GeneralSecurityException) {
+ throw AssertionError("No System TLS: $e", e) // The system has no TLS. Just give up.
+ }
+ }
+
+ override fun toString(): String = javaClass.simpleName
+
+ companion object {
+ @Volatile private var platform = findPlatform()
+
+ const val INFO = 4
+ const val WARN = 5
+
+ private val logger = Logger.getLogger(Platform::class.java.name)
+
+ @JvmStatic
+ fun get(): Platform = platform
+
+ fun resetForTests(platform: Platform = findPlatform()) {
+ Companion.platform = platform
+ }
+
+ fun alpnProtocolNames(protocols: List) =
+ protocols.map { it.name }
+
+ // This explicit check avoids activating in Android Studio with Android specific classes
+ // available when running plugins inside the IDE.
+ val isAndroid: Boolean
+ get() = "Dalvik" == System.getProperty("java.vm.name")
+
+ private val isConscryptPreferred: Boolean
+ get() {
+ val preferredProvider = Security.getProviders()[0].name
+ return "Conscrypt" == preferredProvider
+ }
+
+ private val isOpenJSSEPreferred: Boolean
+ get() {
+ val preferredProvider = Security.getProviders()[0].name
+ return "OpenJSSE" == preferredProvider
+ }
+
+ private val isBouncyCastlePreferred: Boolean
+ get() {
+ val preferredProvider = Security.getProviders()[0].name
+ return "BC" == preferredProvider
+ }
+
+ /** Attempt to match the host runtime to a capable Platform implementation. */
+ private fun findPlatform(): Platform = if (isAndroid) {
+ findAndroidPlatform()
+ } else {
+ findJvmPlatform()
+ }
+
+ private fun findAndroidPlatform(): Platform {
+ return Android10Platform.buildIfSupported() ?: AndroidPlatform.buildIfSupported()!!
+ }
+
+ private fun findJvmPlatform(): Platform {
+ if (isConscryptPreferred) {
+ val conscrypt = ConscryptPlatform.buildIfSupported()
+
+ if (conscrypt != null) {
+ return conscrypt
+ }
+ }
+
+ if (isBouncyCastlePreferred) {
+ val bc = BouncyCastlePlatform.buildIfSupported()
+
+ if (bc != null) {
+ return bc
+ }
+ }
+
+ if (isOpenJSSEPreferred) {
+ val openJSSE = OpenJSSEPlatform.buildIfSupported()
+
+ if (openJSSE != null) {
+ return openJSSE
+ }
+ }
+
+ // An Oracle JDK 9 like OpenJDK, or JDK 8 251+.
+ val jdk9 = Jdk9Platform.buildIfSupported()
+
+ if (jdk9 != null) {
+ return jdk9
+ }
+
+ // An Oracle JDK 8 like OpenJDK, pre 251.
+ val jdkWithJettyBoot = Jdk8WithJettyBootPlatform.buildIfSupported()
+
+ if (jdkWithJettyBoot != null) {
+ return jdkWithJettyBoot
+ }
+
+ return Platform()
+ }
+
+ /**
+ * Returns the concatenation of 8-bit, length prefixed protocol names.
+ * http://tools.ietf.org/html/draft-agl-tls-nextprotoneg-04#page-4
+ */
+ fun concatLengthPrefixed(protocols: List): ByteArray {
+ val result = Buffer()
+ for (protocol in alpnProtocolNames(protocols)) {
+ result.writeByte(protocol.length)
+ result.writeUtf8(protocol)
+ }
+ return result.readByteArray()
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/Android10SocketAdapter.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/Android10SocketAdapter.kt
new file mode 100644
index 00000000..7a34b6f0
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/Android10SocketAdapter.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform.android
+
+import android.annotation.SuppressLint
+import android.net.ssl.SSLSockets
+import android.os.Build
+import java.io.IOException
+import javax.net.ssl.SSLSocket
+import org.eclipse.paho.client.mqttv3.Protocol
+import org.eclipse.paho.client.mqttv3.SuppressSignatureCheck
+import org.eclipse.paho.client.mqttv3.internal.platform.Platform
+import org.eclipse.paho.client.mqttv3.internal.platform.Platform.Companion.isAndroid
+
+/**
+ * Simple non-reflection SocketAdapter for Android Q+.
+ *
+ * These API assumptions make it unsuitable for use on earlier Android versions.
+ */
+@SuppressLint("NewApi")
+@SuppressSignatureCheck
+class Android10SocketAdapter : SocketAdapter {
+ override fun matchesSocket(sslSocket: SSLSocket): Boolean =
+ SSLSockets.isSupportedSocket(sslSocket)
+
+ override fun isSupported(): Boolean = Companion.isSupported()
+
+ @SuppressLint("NewApi")
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? {
+ return try {
+ // SSLSocket.getApplicationProtocol returns "" if application protocols values will not
+ // be used. Observed if you didn't specify SSLParameters.setApplicationProtocols
+ when (val protocol = sslSocket.applicationProtocol) {
+ null, "" -> null
+ else -> protocol
+ }
+ } catch (e: UnsupportedOperationException) {
+ // https://docs.oracle.com/javase/9/docs/api/javax/net/ssl/SSLSocket.html#getApplicationProtocol--
+ null
+ }
+ }
+
+ @SuppressLint("NewApi")
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List
+ ) {
+ try {
+ val sslParameters = sslSocket.sslParameters
+
+ // Enable ALPN.
+ sslParameters.applicationProtocols =
+ Platform.alpnProtocolNames(protocols).toTypedArray()
+
+ sslSocket.sslParameters = sslParameters
+ } catch (iae: IllegalArgumentException) {
+ // probably java.lang.IllegalArgumentException: Invalid input to toASCII from IDN.toASCII
+ throw IOException("Android internal error", iae)
+ }
+ }
+
+ @SuppressSignatureCheck
+ companion object {
+ fun buildIfSupported(): SocketAdapter? =
+ if (isSupported()) Android10SocketAdapter() else null
+
+ fun isSupported() = isAndroid && Build.VERSION.SDK_INT >= 29
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidCertificateChainCleaner.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidCertificateChainCleaner.kt
new file mode 100644
index 00000000..24b6444f
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidCertificateChainCleaner.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform.android
+
+import android.net.http.X509TrustManagerExtensions
+import java.security.cert.Certificate
+import java.security.cert.CertificateException
+import java.security.cert.X509Certificate
+import javax.net.ssl.SSLPeerUnverifiedException
+import javax.net.ssl.X509TrustManager
+import org.eclipse.paho.client.mqttv3.SuppressSignatureCheck
+import org.eclipse.paho.client.mqttv3.internal.tls.CertificateChainCleaner
+
+/**
+ * Android implementation of CertificateChainCleaner using direct Android API calls.
+ * Not used if X509TrustManager doesn't implement [X509TrustManager.checkServerTrusted] with
+ * an additional host param.
+ */
+internal class AndroidCertificateChainCleaner(
+ private val trustManager: X509TrustManager,
+ private val x509TrustManagerExtensions: X509TrustManagerExtensions
+) : CertificateChainCleaner() {
+ @Suppress("UNCHECKED_CAST")
+ @Throws(SSLPeerUnverifiedException::class)
+ @SuppressSignatureCheck
+ override
+ fun clean(chain: List, hostname: String): List {
+ val certificates = (chain as List).toTypedArray()
+ try {
+ return x509TrustManagerExtensions.checkServerTrusted(certificates, "RSA", hostname)
+ } catch (ce: CertificateException) {
+ throw SSLPeerUnverifiedException(ce.message).apply { initCause(ce) }
+ }
+ }
+
+ override fun equals(other: Any?): Boolean =
+ other is AndroidCertificateChainCleaner &&
+ other.trustManager === this.trustManager
+
+ override fun hashCode(): Int = System.identityHashCode(trustManager)
+
+ companion object {
+ @SuppressSignatureCheck
+ fun buildIfSupported(trustManager: X509TrustManager): AndroidCertificateChainCleaner? {
+ val extensions = try {
+ X509TrustManagerExtensions(trustManager)
+ } catch (iae: IllegalArgumentException) {
+ // X509TrustManagerExtensions checks for checkServerTrusted(X509Certificate[], String, String)
+ null
+ }
+
+ return when {
+ extensions != null -> AndroidCertificateChainCleaner(trustManager, extensions)
+ else -> null
+ }
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt
new file mode 100644
index 00000000..f51ef808
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform.android
+
+import java.lang.reflect.InvocationTargetException
+import java.lang.reflect.Method
+import javax.net.ssl.SSLSocket
+import org.eclipse.paho.client.mqttv3.Protocol
+import org.eclipse.paho.client.mqttv3.internal.platform.AndroidPlatform
+import org.eclipse.paho.client.mqttv3.internal.platform.Platform
+import org.eclipse.paho.client.mqttv3.internal.platform.android.DeferredSocketAdapter.Factory
+
+/**
+ * Modern reflection based SocketAdapter for Conscrypt class SSLSockets.
+ *
+ * This is used directly for providers where class name is known e.g. the Google Play Provider
+ * but we can't compile directly against it, or in fact reliably know if it is registered and
+ * on classpath.
+ */
+open class AndroidSocketAdapter(private val sslSocketClass: Class) : SocketAdapter {
+ private val setUseSessionTickets: Method =
+ sslSocketClass.getDeclaredMethod("setUseSessionTickets", Boolean::class.javaPrimitiveType)
+ private val setHostname = sslSocketClass.getMethod("setHostname", String::class.java)
+ private val getAlpnSelectedProtocol = sslSocketClass.getMethod("getAlpnSelectedProtocol")
+ private val setAlpnProtocols =
+ sslSocketClass.getMethod("setAlpnProtocols", ByteArray::class.java)
+
+ override fun isSupported(): Boolean = AndroidPlatform.isSupported
+
+ override fun matchesSocket(sslSocket: SSLSocket): Boolean = sslSocketClass.isInstance(sslSocket)
+
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List
+ ) {
+ // No TLS extensions if the socket class is custom.
+ if (matchesSocket(sslSocket)) {
+ try {
+ // Enable session tickets.
+ setUseSessionTickets.invoke(sslSocket, true)
+
+ if (hostname != null) {
+ // This is SSLParameters.setServerNames() in API 24+.
+ setHostname.invoke(sslSocket, hostname)
+ }
+
+ // Enable ALPN.
+ setAlpnProtocols.invoke(
+ sslSocket,
+ Platform.concatLengthPrefixed(protocols)
+ )
+ } catch (e: IllegalAccessException) {
+ throw AssertionError(e)
+ } catch (e: InvocationTargetException) {
+ throw AssertionError(e)
+ }
+ }
+ }
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? {
+ // No TLS extensions if the socket class is custom.
+ if (!matchesSocket(sslSocket)) {
+ return null
+ }
+
+ return try {
+ val alpnResult = getAlpnSelectedProtocol.invoke(sslSocket) as ByteArray?
+ alpnResult?.toString(Charsets.UTF_8)
+ } catch (e: IllegalAccessException) {
+ throw AssertionError(e)
+ } catch (e: InvocationTargetException) {
+ // https://github.com/square/okhttp/issues/5587
+ val cause = e.cause
+ when {
+ cause is NullPointerException && cause.message == "ssl == null" -> null
+ else -> throw AssertionError(e)
+ }
+ }
+ }
+
+ companion object {
+ val playProviderFactory: Factory =
+ factory("com.google.android.gms.org.conscrypt")
+
+ /**
+ * Builds a SocketAdapter from an observed implementation class, by grabbing the Class
+ * reference to perform reflection on at runtime.
+ *
+ * @param actualSSLSocketClass the runtime class of Conscrypt class socket.
+ */
+ private fun build(actualSSLSocketClass: Class): AndroidSocketAdapter {
+ var possibleClass: Class? = actualSSLSocketClass
+ while (possibleClass != null && possibleClass.simpleName != "OpenSSLSocketImpl") {
+ possibleClass = possibleClass.superclass
+
+ if (possibleClass == null) {
+ throw AssertionError(
+ "No OpenSSLSocketImpl superclass of socket of type $actualSSLSocketClass"
+ )
+ }
+ }
+
+ return AndroidSocketAdapter(possibleClass!!)
+ }
+
+ fun factory(packageName: String): Factory {
+ return object : Factory {
+ override fun matchesSocket(sslSocket: SSLSocket): Boolean =
+ sslSocket.javaClass.name.startsWith("$packageName.")
+
+ override fun create(sslSocket: SSLSocket): SocketAdapter {
+ return build(sslSocket.javaClass)
+ }
+ }
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/BouncyCastleSocketAdapter.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/BouncyCastleSocketAdapter.kt
new file mode 100644
index 00000000..530f9ff8
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/BouncyCastleSocketAdapter.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform.android
+
+import javax.net.ssl.SSLSocket
+import org.bouncycastle.jsse.BCSSLSocket
+import org.eclipse.paho.client.mqttv3.Protocol
+import org.eclipse.paho.client.mqttv3.internal.platform.BouncyCastlePlatform
+import org.eclipse.paho.client.mqttv3.internal.platform.Platform
+import org.eclipse.paho.client.mqttv3.internal.platform.android.DeferredSocketAdapter.Factory
+
+/**
+ * Simple non-reflection SocketAdapter for BouncyCastle.
+ */
+class BouncyCastleSocketAdapter : SocketAdapter {
+ override fun matchesSocket(sslSocket: SSLSocket): Boolean = sslSocket is BCSSLSocket
+
+ override fun isSupported(): Boolean = BouncyCastlePlatform.isSupported
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? {
+ val s = sslSocket as BCSSLSocket
+
+ return when (val protocol = s.applicationProtocol) {
+ null, "" -> null
+ else -> protocol
+ }
+ }
+
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List
+ ) {
+ // No TLS extensions if the socket class is custom.
+ if (matchesSocket(sslSocket)) {
+ val bcSocket = sslSocket as BCSSLSocket
+
+ val sslParameters = bcSocket.parameters
+
+ // Enable ALPN.
+ sslParameters.applicationProtocols = Platform.alpnProtocolNames(protocols).toTypedArray()
+
+ bcSocket.parameters = sslParameters
+ }
+ }
+
+ companion object {
+ val factory = object : Factory {
+ override fun matchesSocket(sslSocket: SSLSocket): Boolean {
+ return BouncyCastlePlatform.isSupported && sslSocket is BCSSLSocket
+ }
+ override fun create(sslSocket: SSLSocket): SocketAdapter = BouncyCastleSocketAdapter()
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/ConscryptSocketAdapter.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/ConscryptSocketAdapter.kt
new file mode 100644
index 00000000..47462765
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/ConscryptSocketAdapter.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform.android
+
+import javax.net.ssl.SSLSocket
+import org.conscrypt.Conscrypt
+import org.eclipse.paho.client.mqttv3.Protocol
+import org.eclipse.paho.client.mqttv3.internal.platform.ConscryptPlatform
+import org.eclipse.paho.client.mqttv3.internal.platform.Platform
+import org.eclipse.paho.client.mqttv3.internal.platform.android.DeferredSocketAdapter.Factory
+
+/**
+ * Simple non-reflection SocketAdapter for Conscrypt when included as an application dependency
+ * directly.
+ */
+class ConscryptSocketAdapter : SocketAdapter {
+ override fun matchesSocket(sslSocket: SSLSocket): Boolean = Conscrypt.isConscrypt(sslSocket)
+
+ override fun isSupported(): Boolean = ConscryptPlatform.isSupported
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? =
+ when {
+ matchesSocket(sslSocket) -> Conscrypt.getApplicationProtocol(sslSocket)
+ else -> null // No TLS extensions if the socket class is custom.
+ }
+
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List
+ ) {
+ // No TLS extensions if the socket class is custom.
+ if (matchesSocket(sslSocket)) {
+ // Enable session tickets.
+ Conscrypt.setUseSessionTickets(sslSocket, true)
+
+ // Enable ALPN.
+ val names = Platform.alpnProtocolNames(protocols)
+ Conscrypt.setApplicationProtocols(sslSocket, names.toTypedArray())
+ }
+ }
+
+ companion object {
+ val factory = object : Factory {
+ override fun matchesSocket(sslSocket: SSLSocket): Boolean {
+ return ConscryptPlatform.isSupported && Conscrypt.isConscrypt(sslSocket)
+ }
+
+ override fun create(sslSocket: SSLSocket): SocketAdapter = ConscryptSocketAdapter()
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/DeferredSocketAdapter.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/DeferredSocketAdapter.kt
new file mode 100644
index 00000000..fb1987d2
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/DeferredSocketAdapter.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform.android
+
+import javax.net.ssl.SSLSocket
+import org.eclipse.paho.client.mqttv3.Protocol
+
+/**
+ * Deferred implementation of SocketAdapter that works by observing the socket
+ * and initializing on first use.
+ *
+ * We use this because eager classpath checks cause confusion and excessive logging in Android,
+ * and we can't rely on classnames after proguard, so are probably best served by falling through
+ * to a situation of trying our least likely noisiest options.
+ */
+class DeferredSocketAdapter(private val socketAdapterFactory: Factory) : SocketAdapter {
+ private var delegate: SocketAdapter? = null
+
+ override fun isSupported(): Boolean {
+ return true
+ }
+
+ override fun matchesSocket(sslSocket: SSLSocket): Boolean =
+ socketAdapterFactory.matchesSocket(sslSocket)
+
+ override fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List
+ ) {
+ getDelegate(sslSocket)?.configureTlsExtensions(sslSocket, hostname, protocols)
+ }
+
+ override fun getSelectedProtocol(sslSocket: SSLSocket): String? {
+ return getDelegate(sslSocket)?.getSelectedProtocol(sslSocket)
+ }
+
+ @Synchronized
+ private fun getDelegate(sslSocket: SSLSocket): SocketAdapter? {
+ if (this.delegate == null && socketAdapterFactory.matchesSocket(sslSocket)) {
+ this.delegate = socketAdapterFactory.create(sslSocket)
+ }
+
+ return delegate
+ }
+
+ interface Factory {
+ fun matchesSocket(sslSocket: SSLSocket): Boolean
+ fun create(sslSocket: SSLSocket): SocketAdapter
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/SocketAdapter.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/SocketAdapter.kt
new file mode 100644
index 00000000..3c2e2cbd
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/SocketAdapter.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform.android
+
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+import org.eclipse.paho.client.mqttv3.Protocol
+
+interface SocketAdapter {
+ fun isSupported(): Boolean
+ fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? = null
+ fun matchesSocket(sslSocket: SSLSocket): Boolean
+ fun matchesSocketFactory(sslSocketFactory: SSLSocketFactory): Boolean = false
+
+ fun configureTlsExtensions(
+ sslSocket: SSLSocket,
+ hostname: String?,
+ protocols: List
+ )
+
+ fun getSelectedProtocol(sslSocket: SSLSocket): String?
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/StandardAndroidSocketAdapter.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/StandardAndroidSocketAdapter.kt
new file mode 100644
index 00000000..43425639
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/StandardAndroidSocketAdapter.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.platform.android
+
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
+import org.eclipse.paho.client.mqttv3.internal.platform.Platform
+import org.eclipse.paho.client.mqttv3.readFieldOrNull
+
+/**
+ * Base Android reflection based SocketAdapter for the built in Android SSLSocket.
+ *
+ * It's assumed to always be present with known class names on Android devices, so we build
+ * optimistically via [buildIfSupported]. But it also doesn't assume a compile time API.
+ */
+class StandardAndroidSocketAdapter(
+ sslSocketClass: Class,
+ private val sslSocketFactoryClass: Class,
+ private val paramClass: Class<*>
+) : AndroidSocketAdapter(sslSocketClass) {
+
+ override fun matchesSocketFactory(sslSocketFactory: SSLSocketFactory): Boolean =
+ sslSocketFactoryClass.isInstance(sslSocketFactory)
+
+ override fun trustManager(sslSocketFactory: SSLSocketFactory): X509TrustManager? {
+ val context: Any? =
+ readFieldOrNull(
+ sslSocketFactory,
+ paramClass,
+ "sslParameters"
+ )
+ val x509TrustManager = readFieldOrNull(
+ context!!,
+ X509TrustManager::class.java,
+ "x509TrustManager"
+ )
+ return x509TrustManager ?: readFieldOrNull(
+ context,
+ X509TrustManager::class.java,
+ "trustManager"
+ )
+ }
+
+ companion object {
+ @Suppress("UNCHECKED_CAST")
+ fun buildIfSupported(packageName: String = "com.android.org.conscrypt"): SocketAdapter? {
+ return try {
+ val sslSocketClass = Class.forName("$packageName.OpenSSLSocketImpl") as Class
+ val sslSocketFactoryClass =
+ Class.forName("$packageName.OpenSSLSocketFactoryImpl") as Class
+ val paramsClass = Class.forName("$packageName.SSLParametersImpl")
+
+ StandardAndroidSocketAdapter(sslSocketClass, sslSocketFactoryClass, paramsClass)
+ } catch (e: Exception) {
+ Platform.get().log(level = Platform.WARN, message = "unable to load android socket classes", t = e)
+ null
+ }
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/BasicCertificateChainCleaner.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/BasicCertificateChainCleaner.kt
new file mode 100644
index 00000000..95691c1f
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/BasicCertificateChainCleaner.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2016 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.tls
+
+import java.security.GeneralSecurityException
+import java.security.cert.Certificate
+import java.security.cert.X509Certificate
+import java.util.ArrayDeque
+import java.util.Deque
+import javax.net.ssl.SSLPeerUnverifiedException
+
+/**
+ * A certificate chain cleaner that uses a set of trusted root certificates to build the trusted
+ * chain. This class duplicates the clean chain building performed during the TLS handshake. We
+ * prefer other mechanisms where they exist, such as with
+ * [okhttp3.internal.platform.AndroidPlatform.AndroidCertificateChainCleaner].
+ *
+ * This class includes code from [Conscrypt's][Conscrypt] [TrustManagerImpl] and
+ * [TrustedCertificateIndex].
+ *
+ * [Conscrypt]: https://conscrypt.org/
+ */
+class BasicCertificateChainCleaner(
+ private val trustRootIndex: TrustRootIndex
+) : CertificateChainCleaner() {
+
+ /**
+ * Returns a cleaned chain for [chain].
+ *
+ * This method throws if the complete chain to a trusted CA certificate cannot be constructed.
+ * This is unexpected unless the trust root index in this class has a different trust manager than
+ * what was used to establish [chain].
+ */
+ @Throws(SSLPeerUnverifiedException::class)
+ override fun clean(chain: List, hostname: String): List {
+ val queue: Deque = ArrayDeque(chain)
+ val result = mutableListOf()
+ result.add(queue.removeFirst())
+ var foundTrustedCertificate = false
+
+ followIssuerChain@
+ for (c in 0 until MAX_SIGNERS) {
+ val toVerify = result[result.size - 1] as X509Certificate
+
+ // If this cert has been signed by a trusted cert, use that. Add the trusted certificate to
+ // the end of the chain unless it's already present. (That would happen if the first
+ // certificate in the chain is itself a self-signed and trusted CA certificate.)
+ val trustedCert = trustRootIndex.findByIssuerAndSignature(toVerify)
+ if (trustedCert != null) {
+ if (result.size > 1 || toVerify != trustedCert) {
+ result.add(trustedCert)
+ }
+ if (verifySignature(trustedCert, trustedCert, result.size - 2)) {
+ return result // The self-signed cert is a root CA. We're done.
+ }
+ foundTrustedCertificate = true
+ continue
+ }
+
+ // Search for the certificate in the chain that signed this certificate. This is typically
+ // the next element in the chain, but it could be any element.
+ val i = queue.iterator()
+ while (i.hasNext()) {
+ val signingCert = i.next() as X509Certificate
+ if (verifySignature(toVerify, signingCert, result.size - 1)) {
+ i.remove()
+ result.add(signingCert)
+ continue@followIssuerChain
+ }
+ }
+
+ // We've reached the end of the chain. If any cert in the chain is trusted, we're done.
+ if (foundTrustedCertificate) {
+ return result
+ }
+
+ // The last link isn't trusted. Fail.
+ throw SSLPeerUnverifiedException(
+ "Failed to find a trusted cert that signed $toVerify"
+ )
+ }
+
+ throw SSLPeerUnverifiedException("Certificate chain too long: $result")
+ }
+
+ /**
+ * Returns true if [toVerify] was signed by [signingCert]'s public key.
+ *
+ * @param minIntermediates the minimum number of intermediate certificates in [signingCert]. This
+ * is -1 if signing cert is a lone self-signed certificate.
+ */
+ private fun verifySignature(
+ toVerify: X509Certificate,
+ signingCert: X509Certificate,
+ minIntermediates: Int
+ ): Boolean {
+ if (toVerify.issuerDN != signingCert.subjectDN) {
+ return false
+ }
+ if (signingCert.basicConstraints < minIntermediates) {
+ return false // The signer can't have this many intermediates beneath it.
+ }
+ return try {
+ toVerify.verify(signingCert.publicKey)
+ true
+ } catch (verifyFailed: GeneralSecurityException) {
+ false
+ }
+ }
+
+ override fun hashCode(): Int {
+ return trustRootIndex.hashCode()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return if (other === this) {
+ true
+ } else {
+ other is BasicCertificateChainCleaner && other.trustRootIndex == trustRootIndex
+ }
+ }
+
+ companion object {
+ private const val MAX_SIGNERS = 9
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/BasicTrustRootIndex.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/BasicTrustRootIndex.kt
new file mode 100644
index 00000000..138ae185
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/BasicTrustRootIndex.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2016 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.tls
+
+import java.security.cert.X509Certificate
+import javax.security.auth.x500.X500Principal
+
+/** A simple index that of trusted root certificates that have been loaded into memory. */
+class BasicTrustRootIndex(vararg caCerts: X509Certificate) : TrustRootIndex {
+ private val subjectToCaCerts: Map>
+
+ init {
+ val map = mutableMapOf>()
+ for (caCert in caCerts) {
+ map.getOrPut(caCert.subjectX500Principal) { mutableSetOf() }.add(caCert)
+ }
+ this.subjectToCaCerts = map
+ }
+
+ override fun findByIssuerAndSignature(cert: X509Certificate): X509Certificate? {
+ val issuer = cert.issuerX500Principal
+ val subjectCaCerts = subjectToCaCerts[issuer] ?: return null
+
+ return subjectCaCerts.firstOrNull {
+ try {
+ cert.verify(it.publicKey)
+ return@firstOrNull true
+ } catch (_: Exception) {
+ return@firstOrNull false
+ }
+ }
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return other === this ||
+ (other is BasicTrustRootIndex && other.subjectToCaCerts == subjectToCaCerts)
+ }
+
+ override fun hashCode(): Int {
+ return subjectToCaCerts.hashCode()
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/CertificateChainCleaner.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/CertificateChainCleaner.kt
new file mode 100644
index 00000000..68a8491e
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/CertificateChainCleaner.kt
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.tls
+
+import java.security.cert.Certificate
+import java.security.cert.X509Certificate
+import javax.net.ssl.SSLPeerUnverifiedException
+import javax.net.ssl.X509TrustManager
+import org.eclipse.paho.client.mqttv3.internal.platform.Platform
+
+/**
+ * Computes the effective certificate chain from the raw array returned by Java's built in TLS APIs.
+ * Cleaning a chain returns a list of certificates where the first element is `chain[0]`, each
+ * certificate is signed by the certificate that follows, and the last certificate is a trusted CA
+ * certificate.
+ *
+ * Use of the chain cleaner is necessary to omit unexpected certificates that aren't relevant to
+ * the TLS handshake and to extract the trusted CA certificate for the benefit of certificate
+ * pinning.
+ */
+abstract class CertificateChainCleaner {
+
+ @Throws(SSLPeerUnverifiedException::class)
+ abstract fun clean(chain: List, hostname: String): List
+
+ companion object {
+ fun get(trustManager: X509TrustManager): CertificateChainCleaner {
+ return Platform.get().buildCertificateChainCleaner(trustManager)
+ }
+
+ fun get(vararg caCerts: X509Certificate): CertificateChainCleaner {
+ return BasicCertificateChainCleaner(BasicTrustRootIndex(*caCerts))
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/CipherSuite.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/CipherSuite.kt
new file mode 100644
index 00000000..03d319f5
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/CipherSuite.kt
@@ -0,0 +1,665 @@
+/*
+ * Copyright (C) 2014 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.tls
+
+/**
+ * [TLS cipher suites][iana_tls_parameters].
+ *
+ * **Not all cipher suites are supported on all platforms.** As newer cipher suites are created (for
+ * stronger privacy, better performance, etc.) they will be adopted by the platform and then exposed
+ * here. Cipher suites that are not available on either Android (through API level 24) or Java
+ * (through JDK 9) are omitted for brevity.
+ *
+ * See [Android SSLEngine][sslengine] which lists the cipher suites supported by Android.
+ *
+ * See [JDK Providers][oracle_providers] which lists the cipher suites supported by Oracle.
+ *
+ * See [NativeCrypto.java][conscrypt_providers] which lists the cipher suites supported by
+ * Conscrypt.
+ *
+ * [iana_tls_parameters]: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml
+ * [sslengine]: https://developer.android.com/reference/javax/net/ssl/SSLEngine.html
+ * [oracle_providers]: https://docs.oracle.com/javase/10/security/oracle-providers.htm
+ * [conscrypt_providers]: https://github.com/google/conscrypt/blob/master/common/src/main/java/org/conscrypt/NativeCrypto.java
+ */
+class CipherSuite private constructor(
+ /**
+ * Returns the Java name of this cipher suite. For some older cipher suites the Java name has the
+ * prefix `SSL_`, causing the Java name to be different from the instance name which is always
+ * prefixed `TLS_`. For example, `TLS_RSA_EXPORT_WITH_RC4_40_MD5.javaName()` is
+ * `"SSL_RSA_EXPORT_WITH_RC4_40_MD5"`.
+ */
+ @get:JvmName("javaName") val javaName: String
+) {
+ @JvmName("-deprecated_javaName")
+ @Deprecated(
+ message = "moved to val",
+ replaceWith = ReplaceWith(expression = "javaName"),
+ level = DeprecationLevel.ERROR
+ )
+ fun javaName(): String = javaName
+
+ override fun toString(): String = javaName
+
+ companion object {
+ /**
+ * Compares cipher suites names like "TLS_RSA_WITH_NULL_MD5" and "SSL_RSA_WITH_NULL_MD5",
+ * ignoring the "TLS_" or "SSL_" prefix which is not consistent across platforms. In particular
+ * some IBM JVMs use the "SSL_" prefix everywhere whereas Oracle JVMs mix "TLS_" and "SSL_".
+ */
+ internal val ORDER_BY_NAME = object : Comparator {
+ override fun compare(a: String, b: String): Int {
+ var i = 4
+ val limit = minOf(a.length, b.length)
+ while (i < limit) {
+ val charA = a[i]
+ val charB = b[i]
+ if (charA != charB) return if (charA < charB) -1 else 1
+ i++
+ }
+ val lengthA = a.length
+ val lengthB = b.length
+ if (lengthA != lengthB) return if (lengthA < lengthB) -1 else 1
+ return 0
+ }
+ }
+
+ /**
+ * Holds interned instances. This needs to be above the init() calls below so that it's
+ * initialized by the time those parts of `()` run. Guarded by CipherSuite.class.
+ */
+ private val INSTANCES = mutableMapOf()
+
+ // Last updated 2016-07-03 using cipher suites from Android 24 and Java 9.
+
+ // @JvmField val TLS_NULL_WITH_NULL_NULL = init("TLS_NULL_WITH_NULL_NULL", 0x0000)
+ @JvmField val TLS_RSA_WITH_NULL_MD5 = init("SSL_RSA_WITH_NULL_MD5", 0x0001)
+
+ @JvmField val TLS_RSA_WITH_NULL_SHA = init("SSL_RSA_WITH_NULL_SHA", 0x0002)
+
+ @JvmField val TLS_RSA_EXPORT_WITH_RC4_40_MD5 =
+ init("SSL_RSA_EXPORT_WITH_RC4_40_MD5", 0x0003)
+
+ @JvmField val TLS_RSA_WITH_RC4_128_MD5 = init("SSL_RSA_WITH_RC4_128_MD5", 0x0004)
+
+ @JvmField val TLS_RSA_WITH_RC4_128_SHA = init("SSL_RSA_WITH_RC4_128_SHA", 0x0005)
+
+ // @JvmField val TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 = init("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 0x0006)
+ // @JvmField val TLS_RSA_WITH_IDEA_CBC_SHA = init("TLS_RSA_WITH_IDEA_CBC_SHA", 0x0007)
+ @JvmField val TLS_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ init("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0008)
+
+ @JvmField val TLS_RSA_WITH_DES_CBC_SHA = init("SSL_RSA_WITH_DES_CBC_SHA", 0x0009)
+
+ @JvmField val TLS_RSA_WITH_3DES_EDE_CBC_SHA = init("SSL_RSA_WITH_3DES_EDE_CBC_SHA", 0x000a)
+
+ // @JvmField val TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x000b)
+ // @JvmField val TLS_DH_DSS_WITH_DES_CBC_SHA = init("TLS_DH_DSS_WITH_DES_CBC_SHA", 0x000c)
+ // @JvmField val TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = init("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", 0x000d)
+ // @JvmField val TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = init("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x000e)
+ // @JvmField val TLS_DH_RSA_WITH_DES_CBC_SHA = init("TLS_DH_RSA_WITH_DES_CBC_SHA", 0x000f)
+ // @JvmField val TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", 0x0010)
+ @JvmField val TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
+ init("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x0011)
+
+ @JvmField val TLS_DHE_DSS_WITH_DES_CBC_SHA = init("SSL_DHE_DSS_WITH_DES_CBC_SHA", 0x0012)
+
+ @JvmField val TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
+ init("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", 0x0013)
+
+ @JvmField val TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ init("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x0014)
+
+ @JvmField val TLS_DHE_RSA_WITH_DES_CBC_SHA = init("SSL_DHE_RSA_WITH_DES_CBC_SHA", 0x0015)
+
+ @JvmField val TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
+ init("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", 0x0016)
+
+ @JvmField val TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 =
+ init("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", 0x0017)
+
+ @JvmField val TLS_DH_anon_WITH_RC4_128_MD5 = init("SSL_DH_anon_WITH_RC4_128_MD5", 0x0018)
+
+ @JvmField val TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA =
+ init("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", 0x0019)
+
+ @JvmField val TLS_DH_anon_WITH_DES_CBC_SHA = init("SSL_DH_anon_WITH_DES_CBC_SHA", 0x001a)
+
+ @JvmField val TLS_DH_anon_WITH_3DES_EDE_CBC_SHA =
+ init("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", 0x001b)
+
+ @JvmField val TLS_KRB5_WITH_DES_CBC_SHA = init("TLS_KRB5_WITH_DES_CBC_SHA", 0x001e)
+
+ @JvmField val TLS_KRB5_WITH_3DES_EDE_CBC_SHA =
+ init("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", 0x001f)
+
+ @JvmField val TLS_KRB5_WITH_RC4_128_SHA = init("TLS_KRB5_WITH_RC4_128_SHA", 0x0020)
+
+ // @JvmField val TLS_KRB5_WITH_IDEA_CBC_SHA = init("TLS_KRB5_WITH_IDEA_CBC_SHA", 0x0021)
+ @JvmField val TLS_KRB5_WITH_DES_CBC_MD5 = init("TLS_KRB5_WITH_DES_CBC_MD5", 0x0022)
+
+ @JvmField val TLS_KRB5_WITH_3DES_EDE_CBC_MD5 =
+ init("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", 0x0023)
+
+ @JvmField val TLS_KRB5_WITH_RC4_128_MD5 = init("TLS_KRB5_WITH_RC4_128_MD5", 0x0024)
+
+ // @JvmField val TLS_KRB5_WITH_IDEA_CBC_MD5 = init("TLS_KRB5_WITH_IDEA_CBC_MD5", 0x0025)
+ @JvmField val TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA =
+ init("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", 0x0026)
+
+ // @JvmField val TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA = init("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x0027)
+ @JvmField val TLS_KRB5_EXPORT_WITH_RC4_40_SHA =
+ init("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", 0x0028)
+
+ @JvmField val TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 =
+ init("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", 0x0029)
+
+ // @JvmField val TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 = init("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x002a)
+ @JvmField val TLS_KRB5_EXPORT_WITH_RC4_40_MD5 =
+ init("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", 0x002b)
+
+ // @JvmField val TLS_PSK_WITH_NULL_SHA = init("TLS_PSK_WITH_NULL_SHA", 0x002c)
+ // @JvmField val TLS_DHE_PSK_WITH_NULL_SHA = init("TLS_DHE_PSK_WITH_NULL_SHA", 0x002d)
+ // @JvmField val TLS_RSA_PSK_WITH_NULL_SHA = init("TLS_RSA_PSK_WITH_NULL_SHA", 0x002e)
+ @JvmField val TLS_RSA_WITH_AES_128_CBC_SHA = init("TLS_RSA_WITH_AES_128_CBC_SHA", 0x002f)
+
+ // @JvmField val TLS_DH_DSS_WITH_AES_128_CBC_SHA = init("TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x0030)
+ // @JvmField val TLS_DH_RSA_WITH_AES_128_CBC_SHA = init("TLS_DH_RSA_WITH_AES_128_CBC_SHA", 0x0031)
+ @JvmField val TLS_DHE_DSS_WITH_AES_128_CBC_SHA =
+ init("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", 0x0032)
+
+ @JvmField val TLS_DHE_RSA_WITH_AES_128_CBC_SHA =
+ init("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", 0x0033)
+
+ @JvmField val TLS_DH_anon_WITH_AES_128_CBC_SHA =
+ init("TLS_DH_anon_WITH_AES_128_CBC_SHA", 0x0034)
+
+ @JvmField val TLS_RSA_WITH_AES_256_CBC_SHA = init("TLS_RSA_WITH_AES_256_CBC_SHA", 0x0035)
+
+ // @JvmField val TLS_DH_DSS_WITH_AES_256_CBC_SHA = init("TLS_DH_DSS_WITH_AES_256_CBC_SHA", 0x0036)
+ // @JvmField val TLS_DH_RSA_WITH_AES_256_CBC_SHA = init("TLS_DH_RSA_WITH_AES_256_CBC_SHA", 0x0037)
+ @JvmField val TLS_DHE_DSS_WITH_AES_256_CBC_SHA =
+ init("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", 0x0038)
+
+ @JvmField val TLS_DHE_RSA_WITH_AES_256_CBC_SHA =
+ init("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", 0x0039)
+
+ @JvmField val TLS_DH_anon_WITH_AES_256_CBC_SHA =
+ init("TLS_DH_anon_WITH_AES_256_CBC_SHA", 0x003a)
+
+ @JvmField val TLS_RSA_WITH_NULL_SHA256 = init("TLS_RSA_WITH_NULL_SHA256", 0x003b)
+
+ @JvmField val TLS_RSA_WITH_AES_128_CBC_SHA256 =
+ init("TLS_RSA_WITH_AES_128_CBC_SHA256", 0x003c)
+
+ @JvmField val TLS_RSA_WITH_AES_256_CBC_SHA256 =
+ init("TLS_RSA_WITH_AES_256_CBC_SHA256", 0x003d)
+
+ // @JvmField val TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = init("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 0x003e)
+ // @JvmField val TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = init("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 0x003f)
+ @JvmField val TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 =
+ init("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", 0x0040)
+
+ @JvmField val TLS_RSA_WITH_CAMELLIA_128_CBC_SHA =
+ init("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0041)
+
+ // @JvmField val TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0042)
+ // @JvmField val TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0043)
+ @JvmField val TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA =
+ init("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0044)
+
+ @JvmField val TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA =
+ init("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0045)
+
+ // @JvmField val TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA = init("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", 0x0046)
+ @JvmField val TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 =
+ init("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", 0x0067)
+
+ // @JvmField val TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = init("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 0x0068)
+ // @JvmField val TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = init("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069)
+ @JvmField val TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 =
+ init("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", 0x006a)
+
+ @JvmField val TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 =
+ init("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", 0x006b)
+
+ @JvmField val TLS_DH_anon_WITH_AES_128_CBC_SHA256 =
+ init("TLS_DH_anon_WITH_AES_128_CBC_SHA256", 0x006c)
+
+ @JvmField val TLS_DH_anon_WITH_AES_256_CBC_SHA256 =
+ init("TLS_DH_anon_WITH_AES_256_CBC_SHA256", 0x006d)
+
+ @JvmField val TLS_RSA_WITH_CAMELLIA_256_CBC_SHA =
+ init("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0084)
+
+ // @JvmField val TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0085)
+ // @JvmField val TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0086)
+ @JvmField val TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA =
+ init("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0087)
+
+ @JvmField val TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA =
+ init("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0088)
+
+ // @JvmField val TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA = init("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", 0x0089)
+ @JvmField val TLS_PSK_WITH_RC4_128_SHA = init("TLS_PSK_WITH_RC4_128_SHA", 0x008a)
+
+ @JvmField val TLS_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 0x008b)
+
+ @JvmField val TLS_PSK_WITH_AES_128_CBC_SHA = init("TLS_PSK_WITH_AES_128_CBC_SHA", 0x008c)
+
+ @JvmField val TLS_PSK_WITH_AES_256_CBC_SHA = init("TLS_PSK_WITH_AES_256_CBC_SHA", 0x008d)
+
+ // @JvmField val TLS_DHE_PSK_WITH_RC4_128_SHA = init("TLS_DHE_PSK_WITH_RC4_128_SHA", 0x008e)
+ // @JvmField val TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", 0x008f)
+ // @JvmField val TLS_DHE_PSK_WITH_AES_128_CBC_SHA = init("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 0x0090)
+ // @JvmField val TLS_DHE_PSK_WITH_AES_256_CBC_SHA = init("TLS_DHE_PSK_WITH_AES_256_CBC_SHA", 0x0091)
+ // @JvmField val TLS_RSA_PSK_WITH_RC4_128_SHA = init("TLS_RSA_PSK_WITH_RC4_128_SHA", 0x0092)
+ // @JvmField val TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", 0x0093)
+ // @JvmField val TLS_RSA_PSK_WITH_AES_128_CBC_SHA = init("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 0x0094)
+ // @JvmField val TLS_RSA_PSK_WITH_AES_256_CBC_SHA = init("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 0x0095)
+ @JvmField val TLS_RSA_WITH_SEED_CBC_SHA = init("TLS_RSA_WITH_SEED_CBC_SHA", 0x0096)
+
+ // @JvmField val TLS_DH_DSS_WITH_SEED_CBC_SHA = init("TLS_DH_DSS_WITH_SEED_CBC_SHA", 0x0097)
+ // @JvmField val TLS_DH_RSA_WITH_SEED_CBC_SHA = init("TLS_DH_RSA_WITH_SEED_CBC_SHA", 0x0098)
+ // @JvmField val TLS_DHE_DSS_WITH_SEED_CBC_SHA = init("TLS_DHE_DSS_WITH_SEED_CBC_SHA", 0x0099)
+ // @JvmField val TLS_DHE_RSA_WITH_SEED_CBC_SHA = init("TLS_DHE_RSA_WITH_SEED_CBC_SHA", 0x009a)
+ // @JvmField val TLS_DH_anon_WITH_SEED_CBC_SHA = init("TLS_DH_anon_WITH_SEED_CBC_SHA", 0x009b)
+ @JvmField val TLS_RSA_WITH_AES_128_GCM_SHA256 =
+ init("TLS_RSA_WITH_AES_128_GCM_SHA256", 0x009c)
+
+ @JvmField val TLS_RSA_WITH_AES_256_GCM_SHA384 =
+ init("TLS_RSA_WITH_AES_256_GCM_SHA384", 0x009d)
+
+ @JvmField val TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 =
+ init("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", 0x009e)
+
+ @JvmField val TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 =
+ init("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", 0x009f)
+
+ // @JvmField val TLS_DH_RSA_WITH_AES_128_GCM_SHA256 = init("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0)
+ // @JvmField val TLS_DH_RSA_WITH_AES_256_GCM_SHA384 = init("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1)
+ @JvmField val TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 =
+ init("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", 0x00a2)
+
+ @JvmField val TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 =
+ init("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", 0x00a3)
+
+ // @JvmField val TLS_DH_DSS_WITH_AES_128_GCM_SHA256 = init("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4)
+ // @JvmField val TLS_DH_DSS_WITH_AES_256_GCM_SHA384 = init("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5)
+ @JvmField val TLS_DH_anon_WITH_AES_128_GCM_SHA256 =
+ init("TLS_DH_anon_WITH_AES_128_GCM_SHA256", 0x00a6)
+
+ @JvmField val TLS_DH_anon_WITH_AES_256_GCM_SHA384 =
+ init("TLS_DH_anon_WITH_AES_256_GCM_SHA384", 0x00a7)
+
+ // @JvmField val TLS_PSK_WITH_AES_128_GCM_SHA256 = init("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8)
+ // @JvmField val TLS_PSK_WITH_AES_256_GCM_SHA384 = init("TLS_PSK_WITH_AES_256_GCM_SHA384", 0x00a9)
+ // @JvmField val TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 = init("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 0x00aa)
+ // @JvmField val TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 = init("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", 0x00ab)
+ // @JvmField val TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 = init("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", 0x00ac)
+ // @JvmField val TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 = init("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", 0x00ad)
+ // @JvmField val TLS_PSK_WITH_AES_128_CBC_SHA256 = init("TLS_PSK_WITH_AES_128_CBC_SHA256", 0x00ae)
+ // @JvmField val TLS_PSK_WITH_AES_256_CBC_SHA384 = init("TLS_PSK_WITH_AES_256_CBC_SHA384", 0x00af)
+ // @JvmField val TLS_PSK_WITH_NULL_SHA256 = init("TLS_PSK_WITH_NULL_SHA256", 0x00b0)
+ // @JvmField val TLS_PSK_WITH_NULL_SHA384 = init("TLS_PSK_WITH_NULL_SHA384", 0x00b1)
+ // @JvmField val TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = init("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", 0x00b2)
+ // @JvmField val TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = init("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", 0x00b3)
+ // @JvmField val TLS_DHE_PSK_WITH_NULL_SHA256 = init("TLS_DHE_PSK_WITH_NULL_SHA256", 0x00b4)
+ // @JvmField val TLS_DHE_PSK_WITH_NULL_SHA384 = init("TLS_DHE_PSK_WITH_NULL_SHA384", 0x00b5)
+ // @JvmField val TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = init("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", 0x00b6)
+ // @JvmField val TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = init("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", 0x00b7)
+ // @JvmField val TLS_RSA_PSK_WITH_NULL_SHA256 = init("TLS_RSA_PSK_WITH_NULL_SHA256", 0x00b8)
+ // @JvmField val TLS_RSA_PSK_WITH_NULL_SHA384 = init("TLS_RSA_PSK_WITH_NULL_SHA384", 0x00b9)
+ // @JvmField val TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00ba)
+ // @JvmField val TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bb)
+ // @JvmField val TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00bc)
+ // @JvmField val TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bd)
+ // @JvmField val TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00be)
+ // @JvmField val TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", 0x00bf)
+ // @JvmField val TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c0)
+ // @JvmField val TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c1)
+ // @JvmField val TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c2)
+ // @JvmField val TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c3)
+ // @JvmField val TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c4)
+ // @JvmField val TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 = init("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 0x00c5)
+ @JvmField val TLS_EMPTY_RENEGOTIATION_INFO_SCSV =
+ init("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", 0x00ff)
+
+ @JvmField val TLS_FALLBACK_SCSV = init("TLS_FALLBACK_SCSV", 0x5600)
+
+ @JvmField val TLS_ECDH_ECDSA_WITH_NULL_SHA = init("TLS_ECDH_ECDSA_WITH_NULL_SHA", 0xc001)
+
+ @JvmField val TLS_ECDH_ECDSA_WITH_RC4_128_SHA =
+ init("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", 0xc002)
+
+ @JvmField val TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA =
+ init("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc003)
+
+ @JvmField val TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA =
+ init("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", 0xc004)
+
+ @JvmField val TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA =
+ init("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", 0xc005)
+
+ @JvmField val TLS_ECDHE_ECDSA_WITH_NULL_SHA = init("TLS_ECDHE_ECDSA_WITH_NULL_SHA", 0xc006)
+
+ @JvmField val TLS_ECDHE_ECDSA_WITH_RC4_128_SHA =
+ init("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", 0xc007)
+
+ @JvmField val TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA =
+ init("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", 0xc008)
+
+ @JvmField val TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA =
+ init("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", 0xc009)
+
+ @JvmField val TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA =
+ init("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", 0xc00a)
+
+ @JvmField val TLS_ECDH_RSA_WITH_NULL_SHA = init("TLS_ECDH_RSA_WITH_NULL_SHA", 0xc00b)
+
+ @JvmField val TLS_ECDH_RSA_WITH_RC4_128_SHA = init("TLS_ECDH_RSA_WITH_RC4_128_SHA", 0xc00c)
+
+ @JvmField val TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA =
+ init("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", 0xc00d)
+
+ @JvmField val TLS_ECDH_RSA_WITH_AES_128_CBC_SHA =
+ init("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", 0xc00e)
+
+ @JvmField val TLS_ECDH_RSA_WITH_AES_256_CBC_SHA =
+ init("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", 0xc00f)
+
+ @JvmField val TLS_ECDHE_RSA_WITH_NULL_SHA = init("TLS_ECDHE_RSA_WITH_NULL_SHA", 0xc010)
+
+ @JvmField val TLS_ECDHE_RSA_WITH_RC4_128_SHA =
+ init("TLS_ECDHE_RSA_WITH_RC4_128_SHA", 0xc011)
+
+ @JvmField val TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA =
+ init("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", 0xc012)
+
+ @JvmField val TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA =
+ init("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", 0xc013)
+
+ @JvmField val TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA =
+ init("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", 0xc014)
+
+ @JvmField val TLS_ECDH_anon_WITH_NULL_SHA = init("TLS_ECDH_anon_WITH_NULL_SHA", 0xc015)
+
+ @JvmField val TLS_ECDH_anon_WITH_RC4_128_SHA =
+ init("TLS_ECDH_anon_WITH_RC4_128_SHA", 0xc016)
+
+ @JvmField val TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA =
+ init("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", 0xc017)
+
+ @JvmField val TLS_ECDH_anon_WITH_AES_128_CBC_SHA =
+ init("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", 0xc018)
+
+ @JvmField val TLS_ECDH_anon_WITH_AES_256_CBC_SHA =
+ init("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", 0xc019)
+
+ // @JvmField val TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = init("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 0xc01a)
+ // @JvmField val TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = init("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 0xc01b)
+ // @JvmField val TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = init("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 0xc01c)
+ // @JvmField val TLS_SRP_SHA_WITH_AES_128_CBC_SHA = init("TLS_SRP_SHA_WITH_AES_128_CBC_SHA", 0xc01d)
+ // @JvmField val TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = init("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 0xc01e)
+ // @JvmField val TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = init("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 0xc01f)
+ // @JvmField val TLS_SRP_SHA_WITH_AES_256_CBC_SHA = init("TLS_SRP_SHA_WITH_AES_256_CBC_SHA", 0xc020)
+ // @JvmField val TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = init("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021)
+ // @JvmField val TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = init("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022)
+ @JvmField val TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 =
+ init("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", 0xc023)
+
+ @JvmField val TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 =
+ init("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", 0xc024)
+
+ @JvmField val TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 =
+ init("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", 0xc025)
+
+ @JvmField val TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 =
+ init("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", 0xc026)
+
+ @JvmField val TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 =
+ init("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", 0xc027)
+
+ @JvmField val TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 =
+ init("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", 0xc028)
+
+ @JvmField val TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 =
+ init("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", 0xc029)
+
+ @JvmField val TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 =
+ init("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", 0xc02a)
+
+ @JvmField val TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 =
+ init("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02b)
+
+ @JvmField val TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 =
+ init("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02c)
+
+ @JvmField val TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 =
+ init("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", 0xc02d)
+
+ @JvmField val TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 =
+ init("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", 0xc02e)
+
+ @JvmField val TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 =
+ init("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", 0xc02f)
+
+ @JvmField val TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 =
+ init("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", 0xc030)
+
+ @JvmField val TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 =
+ init("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", 0xc031)
+
+ @JvmField val TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 =
+ init("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", 0xc032)
+
+ // @JvmField val TLS_ECDHE_PSK_WITH_RC4_128_SHA = init("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033)
+ // @JvmField val TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA = init("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034)
+ @JvmField val TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA =
+ init("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 0xc035)
+
+ @JvmField val TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA =
+ init("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 0xc036)
+
+ // @JvmField val TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = init("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 0xc037)
+ // @JvmField val TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 = init("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 0xc038)
+ // @JvmField val TLS_ECDHE_PSK_WITH_NULL_SHA = init("TLS_ECDHE_PSK_WITH_NULL_SHA", 0xc039)
+ // @JvmField val TLS_ECDHE_PSK_WITH_NULL_SHA256 = init("TLS_ECDHE_PSK_WITH_NULL_SHA256", 0xc03a)
+ // @JvmField val TLS_ECDHE_PSK_WITH_NULL_SHA384 = init("TLS_ECDHE_PSK_WITH_NULL_SHA384", 0xc03b)
+ // @JvmField val TLS_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_RSA_WITH_ARIA_128_CBC_SHA256", 0xc03c)
+ // @JvmField val TLS_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_RSA_WITH_ARIA_256_CBC_SHA384", 0xc03d)
+ // @JvmField val TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 = init("TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", 0xc03e)
+ // @JvmField val TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 = init("TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", 0xc03f)
+ // @JvmField val TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc040)
+ // @JvmField val TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc041)
+ // @JvmField val TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 = init("TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", 0xc042)
+ // @JvmField val TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 = init("TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", 0xc043)
+ // @JvmField val TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc044)
+ // @JvmField val TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc045)
+ // @JvmField val TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 = init("TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", 0xc046)
+ // @JvmField val TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 = init("TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", 0xc047)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc048)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc049)
+ // @JvmField val TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc04a)
+ // @JvmField val TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc04b)
+ // @JvmField val TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04c)
+ // @JvmField val TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04d)
+ // @JvmField val TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04e)
+ // @JvmField val TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04f)
+ // @JvmField val TLS_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_RSA_WITH_ARIA_128_GCM_SHA256", 0xc050)
+ // @JvmField val TLS_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_RSA_WITH_ARIA_256_GCM_SHA384", 0xc051)
+ // @JvmField val TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc052)
+ // @JvmField val TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc053)
+ // @JvmField val TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc054)
+ // @JvmField val TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc055)
+ // @JvmField val TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 = init("TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", 0xc056)
+ // @JvmField val TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 = init("TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", 0xc057)
+ // @JvmField val TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 = init("TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", 0xc058)
+ // @JvmField val TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 = init("TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", 0xc059)
+ // @JvmField val TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 = init("TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", 0xc05a)
+ // @JvmField val TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 = init("TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", 0xc05b)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05c)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05d)
+ // @JvmField val TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05e)
+ // @JvmField val TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05f)
+ // @JvmField val TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc060)
+ // @JvmField val TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc061)
+ // @JvmField val TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 = init("TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc062)
+ // @JvmField val TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 = init("TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc063)
+ // @JvmField val TLS_PSK_WITH_ARIA_128_CBC_SHA256 = init("TLS_PSK_WITH_ARIA_128_CBC_SHA256", 0xc064)
+ // @JvmField val TLS_PSK_WITH_ARIA_256_CBC_SHA384 = init("TLS_PSK_WITH_ARIA_256_CBC_SHA384", 0xc065)
+ // @JvmField val TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 = init("TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc066)
+ // @JvmField val TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 = init("TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc067)
+ // @JvmField val TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 = init("TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", 0xc068)
+ // @JvmField val TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 = init("TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", 0xc069)
+ // @JvmField val TLS_PSK_WITH_ARIA_128_GCM_SHA256 = init("TLS_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06a)
+ // @JvmField val TLS_PSK_WITH_ARIA_256_GCM_SHA384 = init("TLS_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06b)
+ // @JvmField val TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 = init("TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06c)
+ // @JvmField val TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 = init("TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06d)
+ // @JvmField val TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 = init("TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06e)
+ // @JvmField val TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 = init("TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06f)
+ // @JvmField val TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 = init("TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc070)
+ // @JvmField val TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 = init("TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc071)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc072)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc073)
+ // @JvmField val TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc074)
+ // @JvmField val TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc075)
+ // @JvmField val TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc076)
+ // @JvmField val TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc077)
+ // @JvmField val TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc078)
+ // @JvmField val TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc079)
+ // @JvmField val TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07a)
+ // @JvmField val TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07b)
+ // @JvmField val TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07c)
+ // @JvmField val TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07d)
+ // @JvmField val TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07e)
+ // @JvmField val TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07f)
+ // @JvmField val TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc080)
+ // @JvmField val TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc081)
+ // @JvmField val TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc082)
+ // @JvmField val TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc083)
+ // @JvmField val TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", 0xc084)
+ // @JvmField val TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", 0xc085)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc086)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc087)
+ // @JvmField val TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc088)
+ // @JvmField val TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc089)
+ // @JvmField val TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08a)
+ // @JvmField val TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08b)
+ // @JvmField val TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08c)
+ // @JvmField val TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08d)
+ // @JvmField val TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc08e)
+ // @JvmField val TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc08f)
+ // @JvmField val TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc090)
+ // @JvmField val TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc091)
+ // @JvmField val TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 = init("TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc092)
+ // @JvmField val TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 = init("TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc093)
+ // @JvmField val TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc094)
+ // @JvmField val TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc095)
+ // @JvmField val TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc096)
+ // @JvmField val TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc097)
+ // @JvmField val TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc098)
+ // @JvmField val TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc099)
+ // @JvmField val TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 = init("TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc09a)
+ // @JvmField val TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 = init("TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc09b)
+ // @JvmField val TLS_RSA_WITH_AES_128_CCM = init("TLS_RSA_WITH_AES_128_CCM", 0xc09c)
+ // @JvmField val TLS_RSA_WITH_AES_256_CCM = init("TLS_RSA_WITH_AES_256_CCM", 0xc09d)
+ // @JvmField val TLS_DHE_RSA_WITH_AES_128_CCM = init("TLS_DHE_RSA_WITH_AES_128_CCM", 0xc09e)
+ // @JvmField val TLS_DHE_RSA_WITH_AES_256_CCM = init("TLS_DHE_RSA_WITH_AES_256_CCM", 0xc09f)
+ // @JvmField val TLS_RSA_WITH_AES_128_CCM_8 = init("TLS_RSA_WITH_AES_128_CCM_8", 0xc0a0)
+ // @JvmField val TLS_RSA_WITH_AES_256_CCM_8 = init("TLS_RSA_WITH_AES_256_CCM_8", 0xc0a1)
+ // @JvmField val TLS_DHE_RSA_WITH_AES_128_CCM_8 = init("TLS_DHE_RSA_WITH_AES_128_CCM_8", 0xc0a2)
+ // @JvmField val TLS_DHE_RSA_WITH_AES_256_CCM_8 = init("TLS_DHE_RSA_WITH_AES_256_CCM_8", 0xc0a3)
+ // @JvmField val TLS_PSK_WITH_AES_128_CCM = init("TLS_PSK_WITH_AES_128_CCM", 0xc0a4)
+ // @JvmField val TLS_PSK_WITH_AES_256_CCM = init("TLS_PSK_WITH_AES_256_CCM", 0xc0a5)
+ // @JvmField val TLS_DHE_PSK_WITH_AES_128_CCM = init("TLS_DHE_PSK_WITH_AES_128_CCM", 0xc0a6)
+ // @JvmField val TLS_DHE_PSK_WITH_AES_256_CCM = init("TLS_DHE_PSK_WITH_AES_256_CCM", 0xc0a7)
+ // @JvmField val TLS_PSK_WITH_AES_128_CCM_8 = init("TLS_PSK_WITH_AES_128_CCM_8", 0xc0a8)
+ // @JvmField val TLS_PSK_WITH_AES_256_CCM_8 = init("TLS_PSK_WITH_AES_256_CCM_8", 0xc0a9)
+ // @JvmField val TLS_PSK_DHE_WITH_AES_128_CCM_8 = init("TLS_PSK_DHE_WITH_AES_128_CCM_8", 0xc0aa)
+ // @JvmField val TLS_PSK_DHE_WITH_AES_256_CCM_8 = init("TLS_PSK_DHE_WITH_AES_256_CCM_8", 0xc0ab)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_AES_128_CCM = init("TLS_ECDHE_ECDSA_WITH_AES_128_CCM", 0xc0ac)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_AES_256_CCM = init("TLS_ECDHE_ECDSA_WITH_AES_256_CCM", 0xc0ad)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = init("TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", 0xc0ae)
+ // @JvmField val TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 = init("TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", 0xc0af)
+ @JvmField val TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 =
+ init("TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 0xcca8)
+
+ @JvmField val TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 =
+ init("TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", 0xcca9)
+
+ @JvmField val TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 =
+ init("TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", 0xccaa)
+
+ // @JvmField val TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccab)
+ @JvmField val TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 =
+ init("TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccac)
+
+ // @JvmField val TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccad)
+ // @JvmField val TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 = init("TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256", 0xccae)
+
+ // TLS 1.3 https://tools.ietf.org/html/rfc8446
+ @JvmField val TLS_AES_128_GCM_SHA256 = init("TLS_AES_128_GCM_SHA256", 0x1301)
+
+ @JvmField val TLS_AES_256_GCM_SHA384 = init("TLS_AES_256_GCM_SHA384", 0x1302)
+
+ @JvmField val TLS_CHACHA20_POLY1305_SHA256 = init("TLS_CHACHA20_POLY1305_SHA256", 0x1303)
+
+ @JvmField val TLS_AES_128_CCM_SHA256 = init("TLS_AES_128_CCM_SHA256", 0x1304)
+
+ @JvmField val TLS_AES_128_CCM_8_SHA256 = init("TLS_AES_128_CCM_8_SHA256", 0x1305)
+
+ /**
+ * @param javaName the name used by Java APIs for this cipher suite. Different than the IANA
+ * name for older cipher suites because the prefix is `SSL_` instead of `TLS_`.
+ */
+ @JvmStatic
+ @Synchronized
+ fun forJavaName(javaName: String): CipherSuite {
+ var result: CipherSuite? = INSTANCES[javaName]
+ if (result == null) {
+ result = INSTANCES[secondaryName(javaName)]
+
+ if (result == null) {
+ result = CipherSuite(javaName)
+ }
+
+ // Add the new cipher suite, or a confirmed alias.
+ INSTANCES[javaName] = result
+ }
+ return result
+ }
+
+ private fun secondaryName(javaName: String): String {
+ return when {
+ javaName.startsWith("TLS_") -> "SSL_" + javaName.substring(4)
+ javaName.startsWith("SSL_") -> "TLS_" + javaName.substring(4)
+ else -> javaName
+ }
+ }
+
+ /**
+ * @param javaName the name used by Java APIs for this cipher suite. Different than the IANA
+ * name for older cipher suites because the prefix is `SSL_` instead of `TLS_`.
+ * @param value the integer identifier for this cipher suite. (Documentation only.)
+ */
+ private fun init(javaName: String, value: Int): CipherSuite {
+ val suite = CipherSuite(javaName)
+ INSTANCES[javaName] = suite
+ return suite
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/TlsVersion.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/TlsVersion.kt
new file mode 100644
index 00000000..1b250865
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/TlsVersion.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.tls
+
+/**
+ * Versions of TLS that can be offered when negotiating a secure socket. See
+ * [javax.net.ssl.SSLSocket.setEnabledProtocols].
+ */
+enum class TlsVersion(
+ @get:JvmName("javaName") val javaName: String
+) {
+ TLS_1_3("TLSv1.3"), // 2016.
+ TLS_1_2("TLSv1.2"), // 2008.
+ TLS_1_1("TLSv1.1"), // 2006.
+ TLS_1_0("TLSv1"), // 1999.
+ SSL_3_0("SSLv3"); // 1996.
+
+ @JvmName("-deprecated_javaName")
+ @Deprecated(
+ message = "moved to val",
+ replaceWith = ReplaceWith(expression = "javaName"),
+ level = DeprecationLevel.ERROR
+ )
+ fun javaName(): String = javaName
+
+ companion object {
+ @JvmStatic
+ fun forJavaName(javaName: String): TlsVersion {
+ return when (javaName) {
+ "TLSv1.3" -> TLS_1_3
+ "TLSv1.2" -> TLS_1_2
+ "TLSv1.1" -> TLS_1_1
+ "TLSv1" -> TLS_1_0
+ "SSLv3" -> SSL_3_0
+ else -> throw IllegalArgumentException("Unexpected TLS version: $javaName")
+ }
+ }
+ }
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/TrustRootIndex.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/TrustRootIndex.kt
new file mode 100644
index 00000000..4f3662be
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/tls/TrustRootIndex.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 Square, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.eclipse.paho.client.mqttv3.internal.tls
+
+import java.security.cert.X509Certificate
+
+fun interface TrustRootIndex {
+ /** Returns the trusted CA certificate that signed [cert]. */
+ fun findByIssuerAndSignature(cert: X509Certificate): X509Certificate?
+}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/websocket/ExtendedByteArrayOutputStream.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/websocket/ExtendedByteArrayOutputStream.java
index d8fabe06..fbeaa31c 100755
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/websocket/ExtendedByteArrayOutputStream.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/websocket/ExtendedByteArrayOutputStream.java
@@ -9,15 +9,24 @@ class ExtendedByteArrayOutputStream extends ByteArrayOutputStream {
final WebSocketNetworkModule webSocketNetworkModule;
final WebSocketSecureNetworkModule webSocketSecureNetworkModule;
+ final WebSocketSecureNetworkModuleV2 webSocketSecureNetworkModuleV2;
ExtendedByteArrayOutputStream(WebSocketNetworkModule module) {
this.webSocketNetworkModule = module;
this.webSocketSecureNetworkModule = null;
+ this.webSocketSecureNetworkModuleV2 = null;
}
ExtendedByteArrayOutputStream(WebSocketSecureNetworkModule module) {
this.webSocketNetworkModule = null;
this.webSocketSecureNetworkModule = module;
+ this.webSocketSecureNetworkModuleV2 = null;
+ }
+
+ ExtendedByteArrayOutputStream(WebSocketSecureNetworkModuleV2 module) {
+ this.webSocketNetworkModule = null;
+ this.webSocketSecureNetworkModule = null;
+ this.webSocketSecureNetworkModuleV2 = module;
}
public void flush() throws IOException {
@@ -41,6 +50,9 @@ OutputStream getSocketOutputStream() throws IOException {
if(webSocketSecureNetworkModule != null){
return webSocketSecureNetworkModule.getSocketOutputStream();
}
+ if(webSocketSecureNetworkModuleV2 != null) {
+ return webSocketSecureNetworkModuleV2.getSocketOutputStream();
+ }
return null;
}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/websocket/WebSocketSecureNetworkModuleV2.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/websocket/WebSocketSecureNetworkModuleV2.java
new file mode 100755
index 00000000..98e70410
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/websocket/WebSocketSecureNetworkModuleV2.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * James Sutton - Bug 459142 - WebSocket support for the Java client.
+ */
+package org.eclipse.paho.client.mqttv3.internal.websocket;
+
+import org.eclipse.paho.client.mqttv3.ConnectionSpec;
+import org.eclipse.paho.client.mqttv3.ILogger;
+import org.eclipse.paho.client.mqttv3.IPahoEvents;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.Protocol;
+import org.eclipse.paho.client.mqttv3.internal.SSLNetworkModuleV2;
+import org.eclipse.paho.client.mqttv3.internal.tls.CertificateChainCleaner;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.X509TrustManager;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class WebSocketSecureNetworkModuleV2 extends SSLNetworkModuleV2 {
+
+ private static final String CLASS_NAME = WebSocketSecureNetworkModuleV2.class.getName();
+
+ private PipedInputStream pipedInputStream;
+ private WebSocketReceiver webSocketReceiver;
+ private String uri;
+ private String host;
+ private int port;
+ private ILogger logger;
+ ByteBuffer recievedPayload;
+
+ /**
+ * Overrides the flush method.
+ * This allows us to encode the MQTT payload into a WebSocket
+ * Frame before passing it through to the real socket.
+ */
+ private ByteArrayOutputStream outputStream = new ExtendedByteArrayOutputStream(this);
+
+ public WebSocketSecureNetworkModuleV2(
+ SocketFactory socketFactory,
+ SSLSocketFactory sslSocketFactory,
+ X509TrustManager x509TrustManager,
+ ConnectionSpec connectionSpec,
+ List alpnProtocolList,
+ String uri,
+ String host,
+ int port,
+ String clientId,
+ ILogger logger,
+ IPahoEvents pahoEvents
+ ) {
+ super(
+ socketFactory,
+ sslSocketFactory,
+ x509TrustManager,
+ connectionSpec,
+ alpnProtocolList,
+ host,
+ port,
+ clientId,
+ logger,
+ pahoEvents
+ );
+ this.uri = uri;
+ this.host = host;
+ this.port = port;
+ this.logger = logger;
+ this.pipedInputStream = new PipedInputStream();
+ }
+
+ public void start() throws IOException, MqttException {
+ super.start();
+ WebSocketHandshake handshake = new WebSocketHandshake(super.getInputStream(),
+ super.getOutputStream(), uri, host, port);
+ handshake.execute();
+ this.webSocketReceiver = new WebSocketReceiver(getSocketInputStream(), pipedInputStream);
+ webSocketReceiver.start("WssSocketReceiver");
+
+ }
+
+ OutputStream getSocketOutputStream() throws IOException {
+ return super.getOutputStream();
+ }
+
+ InputStream getSocketInputStream() throws IOException {
+ return super.getInputStream();
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return pipedInputStream;
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return outputStream;
+ }
+
+ public void stop() throws IOException {
+ // Creating Close Frame
+ WebSocketFrame frame = new WebSocketFrame((byte) 0x08, true, "1000".getBytes());
+ byte[] rawFrame = frame.encodeFrame();
+ getSocketOutputStream().write(rawFrame);
+ getSocketOutputStream().flush();
+
+ if (webSocketReceiver != null) {
+ webSocketReceiver.stop();
+ }
+ super.stop();
+ }
+
+ public String getServerURI() {
+ return "wss://" + host + ":" + port;
+ }
+
+
+}
diff --git a/paho/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/paho/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
new file mode 100644
index 00000000..ca6ee9ce
--- /dev/null
+++ b/paho/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
@@ -0,0 +1 @@
+mock-maker-inline
\ No newline at end of file
diff --git a/pingsender/timer-pingsender/build.gradle.kts b/pingsender/timer-pingsender/build.gradle.kts
index f7231086..1da60e96 100644
--- a/pingsender/timer-pingsender/build.gradle.kts
+++ b/pingsender/timer-pingsender/build.gradle.kts
@@ -35,6 +35,7 @@ dependencies {
implementation(project(":courier-core-android"))
implementation(deps.android.androidx.annotation)
+ testImplementation(deps.android.test.mockitoCore)
testImplementation(deps.android.test.kotlinTestJunit)
}
diff --git a/pingsender/workmanager-2.6.0-pingsender/build.gradle.kts b/pingsender/workmanager-2.6.0-pingsender/build.gradle.kts
index 8fd8b586..d1ae1f36 100644
--- a/pingsender/workmanager-2.6.0-pingsender/build.gradle.kts
+++ b/pingsender/workmanager-2.6.0-pingsender/build.gradle.kts
@@ -32,7 +32,7 @@ dependencies {
api(project(":mqtt-pingsender"))
implementation(project(":courier-core-android"))
implementation(deps.workManager.runtime_2_6_0)
-
+ testImplementation(deps.android.test.mockitoCore)
testImplementation(deps.android.test.kotlinTestJunit)
}
diff --git a/pingsender/workmanager-pingsender/build.gradle.kts b/pingsender/workmanager-pingsender/build.gradle.kts
index f9097570..07352792 100644
--- a/pingsender/workmanager-pingsender/build.gradle.kts
+++ b/pingsender/workmanager-pingsender/build.gradle.kts
@@ -35,7 +35,7 @@ dependencies {
api(project(":mqtt-pingsender"))
implementation(project(":courier-core-android"))
implementation(deps.workManager.runtime)
-
+ testImplementation(deps.android.test.mockitoCore)
testImplementation(deps.android.test.kotlinTestJunit)
}
From 5bee5771a3ed06bace9723c417c1a5425d213bae Mon Sep 17 00:00:00 2001
From: Anubhav Gupta
Date: Wed, 28 Sep 2022 15:45:56 +0530
Subject: [PATCH 03/25] removed java 11 depedency (#45)
Co-authored-by: Anubhav Gupta
---
build.gradle.kts | 6 +++---
paho/build.gradle.kts | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index 9119f06d..a3c80aa8 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -41,12 +41,12 @@ allprojects {
subprojects {
tasks.withType().configureEach {
kotlinOptions {
- jvmTarget = "11"
+ jvmTarget = "1.8"
}
}
tasks.withType().configureEach {
- sourceCompatibility = JavaVersion.VERSION_11.toString()
- targetCompatibility = JavaVersion.VERSION_11.toString()
+ sourceCompatibility = JavaVersion.VERSION_1_8.toString()
+ targetCompatibility = JavaVersion.VERSION_1_8.toString()
}
}
diff --git a/paho/build.gradle.kts b/paho/build.gradle.kts
index 6ef57762..cf078729 100644
--- a/paho/build.gradle.kts
+++ b/paho/build.gradle.kts
@@ -16,8 +16,8 @@ plugins {
}
java {
- sourceCompatibility = JavaVersion.VERSION_11
- targetCompatibility = JavaVersion.VERSION_11
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
}
dependencies {
From 49c1ebbecd48cc793ee5d170a25175ba19f3c215 Mon Sep 17 00:00:00 2001
From: Juan Sebastian sanchez
Date: Fri, 7 Oct 2022 04:27:24 -0500
Subject: [PATCH 04/25] Update com.google.code.gson dependecy (#47)
In order to fix vulnerability reported on https://security.snyk.io/vuln/SNYK-JAVA-COMGOOGLECODEGSON-1730327
---
dependencies.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dependencies.gradle b/dependencies.gradle
index 080678c4..11eecb84 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -6,6 +6,6 @@ ext {
kotlinCoroutines = 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2'
kotlinCoroutinesRxInterop = 'org.jetbrains.kotlinx:kotlinx-coroutines-reactive:1.3.2'
- gson = 'com.google.code.gson:gson:2.8.5'
+ gson = 'com.google.code.gson:gson:2.8.9'
okio = 'com.squareup.okio:okio:1.13.0'
}
\ No newline at end of file
From fba09e5523cd2fa5e081cc3b5eef54d5fccb5bfd Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Fri, 28 Oct 2022 11:47:08 +0530
Subject: [PATCH 05/25] Remove empty username check (#49)
---
.../src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt | 1 -
.../java/org/eclipse/paho/client/mqttv3/MqttConnectOptions.java | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt b/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
index 69592f2f..d90d7c12 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
@@ -111,7 +111,6 @@ class MqttConnectOptions private constructor(
}
fun userName(username: String) = apply {
- require(username.isNotEmpty()) { "username cannot be empty" }
this.username = username
}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttConnectOptions.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttConnectOptions.java
index 767a77a3..1d2e6044 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttConnectOptions.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttConnectOptions.java
@@ -162,7 +162,7 @@ public void setUserName(String userName)
{
if ((userName != null) && (userName.trim().equals("")))
{
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException("Username is empty");
}
this.userName = userName;
}
From 09892e0dcf6165ca0b213b543e8c1aee1f250c5b Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Sun, 30 Oct 2022 12:32:50 +0530
Subject: [PATCH 06/25] Add topic & content-type in message adapter (#48)
* Add topic & content-type in message adapter
---
courier-core/api/courier-core.api | 5 ++--
.../java/com/gojek/courier/MessageAdapter.kt | 7 ++++--
.../messageadapter/gson/GsonMessageAdapter.kt | 6 +++--
.../moshi/MoshiMessageAdapter.kt | 6 +++--
.../protobuf/ProtobufMessageAdapter.kt | 6 +++--
.../gojek/courier/coordinator/Coordinator.kt | 24 ++++++++++++-------
.../builtin/ByteArrayMessageAdapter.kt | 6 +++--
.../builtin/TextMessageAdapter.kt | 6 +++--
8 files changed, 44 insertions(+), 22 deletions(-)
diff --git a/courier-core/api/courier-core.api b/courier-core/api/courier-core.api
index 055044f4..e4ca55c0 100644
--- a/courier-core/api/courier-core.api
+++ b/courier-core/api/courier-core.api
@@ -8,8 +8,9 @@ public final class com/gojek/courier/Message$Bytes : com/gojek/courier/Message {
}
public abstract interface class com/gojek/courier/MessageAdapter {
- public abstract fun fromMessage (Lcom/gojek/courier/Message;)Ljava/lang/Object;
- public abstract fun toMessage (Ljava/lang/Object;)Lcom/gojek/courier/Message;
+ public abstract fun contentType ()Ljava/lang/String;
+ public abstract fun fromMessage (Ljava/lang/String;Lcom/gojek/courier/Message;)Ljava/lang/Object;
+ public abstract fun toMessage (Ljava/lang/String;Ljava/lang/Object;)Lcom/gojek/courier/Message;
}
public abstract interface class com/gojek/courier/MessageAdapter$Factory {
diff --git a/courier-core/src/main/java/com/gojek/courier/MessageAdapter.kt b/courier-core/src/main/java/com/gojek/courier/MessageAdapter.kt
index 665d4d8a..3e4085a7 100644
--- a/courier-core/src/main/java/com/gojek/courier/MessageAdapter.kt
+++ b/courier-core/src/main/java/com/gojek/courier/MessageAdapter.kt
@@ -5,10 +5,13 @@ import java.lang.reflect.Type
interface MessageAdapter {
/** Returns an object of type `T` that represents a [Message]. */
- fun fromMessage(message: Message): T
+ fun fromMessage(topic: String, message: Message): T
/** Returns a [Message] that represents [data]. */
- fun toMessage(data: T): Message
+ fun toMessage(topic: String, data: T): Message
+
+ /** Returns the content type supported by this adapter. */
+ fun contentType(): String
/** Creates [MessageAdapter] instances based on a type and target usage. */
interface Factory {
diff --git a/courier-message-adapter-gson/src/main/java/com/gojek/courier/messageadapter/gson/GsonMessageAdapter.kt b/courier-message-adapter-gson/src/main/java/com/gojek/courier/messageadapter/gson/GsonMessageAdapter.kt
index 0239c442..03e27a74 100644
--- a/courier-message-adapter-gson/src/main/java/com/gojek/courier/messageadapter/gson/GsonMessageAdapter.kt
+++ b/courier-message-adapter-gson/src/main/java/com/gojek/courier/messageadapter/gson/GsonMessageAdapter.kt
@@ -19,7 +19,7 @@ private class GsonMessageAdapter constructor(
private val typeAdapter: TypeAdapter
) : MessageAdapter {
- override fun fromMessage(message: Message): T {
+ override fun fromMessage(topic: String, message: Message): T {
val stringValue = when (message) {
is Message.Bytes -> String(message.value)
}
@@ -27,7 +27,7 @@ private class GsonMessageAdapter constructor(
return typeAdapter.read(jsonReader)!!
}
- override fun toMessage(data: T): Message {
+ override fun toMessage(topic: String, data: T): Message {
val buffer = Buffer()
val writer = OutputStreamWriter(buffer.outputStream(), UTF_8)
val jsonWriter = gson.newJsonWriter(writer)
@@ -36,6 +36,8 @@ private class GsonMessageAdapter constructor(
val stringValue = buffer.readByteString().utf8()
return Message.Bytes(stringValue.toByteArray())
}
+
+ override fun contentType() = "application/json"
}
class GsonMessageAdapterFactory(
diff --git a/courier-message-adapter-moshi/src/main/java/com/gojek/courier/messageadapter/moshi/MoshiMessageAdapter.kt b/courier-message-adapter-moshi/src/main/java/com/gojek/courier/messageadapter/moshi/MoshiMessageAdapter.kt
index c6cd0945..1ba6152a 100644
--- a/courier-message-adapter-moshi/src/main/java/com/gojek/courier/messageadapter/moshi/MoshiMessageAdapter.kt
+++ b/courier-message-adapter-moshi/src/main/java/com/gojek/courier/messageadapter/moshi/MoshiMessageAdapter.kt
@@ -16,7 +16,7 @@ private class MoshiMessageAdapter constructor(
private val jsonAdapter: JsonAdapter
) : MessageAdapter {
- override fun fromMessage(message: Message): T {
+ override fun fromMessage(topic: String, message: Message): T {
val stringValue = when (message) {
is Message.Bytes -> {
val byteString = ByteString.of(message.value, 0, message.value.size)
@@ -32,11 +32,13 @@ private class MoshiMessageAdapter constructor(
return jsonAdapter.fromJson(stringValue)!!
}
- override fun toMessage(data: T): Message {
+ override fun toMessage(topic: String, data: T): Message {
val stringValue = jsonAdapter.toJson(data)
return Message.Bytes(stringValue.toByteArray())
}
+ override fun contentType() = "application/json"
+
private companion object {
private val UTF8_BOM = ByteString.decodeHex("EFBBBF")
}
diff --git a/courier-message-adapter-protobuf/src/main/java/com/gojek/courier/messageadapter/protobuf/ProtobufMessageAdapter.kt b/courier-message-adapter-protobuf/src/main/java/com/gojek/courier/messageadapter/protobuf/ProtobufMessageAdapter.kt
index 3e583b19..3bf1044d 100644
--- a/courier-message-adapter-protobuf/src/main/java/com/gojek/courier/messageadapter/protobuf/ProtobufMessageAdapter.kt
+++ b/courier-message-adapter-protobuf/src/main/java/com/gojek/courier/messageadapter/protobuf/ProtobufMessageAdapter.kt
@@ -17,7 +17,7 @@ private class ProtobufMessageAdapter constructor(
private val registry: ExtensionRegistryLite?
) : MessageAdapter {
- override fun fromMessage(message: Message): T {
+ override fun fromMessage(topic: String, message: Message): T {
val bytesValue = when (message) {
is Message.Bytes -> message.value
}
@@ -31,7 +31,9 @@ private class ProtobufMessageAdapter constructor(
}
}
- override fun toMessage(data: T): Message = Message.Bytes(data.toByteArray())
+ override fun toMessage(topic: String, data: T): Message = Message.Bytes(data.toByteArray())
+
+ override fun contentType() = "application/x-protobuf"
}
class ProtobufMessageAdapterFactory(
diff --git a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
index c3a906d1..a4f7253a 100644
--- a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
+++ b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
@@ -23,9 +23,9 @@ internal class Coordinator(
@Synchronized
override fun send(stubMethod: StubMethod.Send, args: Array): Any {
val data = stubMethod.argumentProcessor.getDataArgument(args)
- val message = stubMethod.messageAdapter.toMessage(data)
- stubMethod.argumentProcessor.inject(args)
val topic = stubMethod.argumentProcessor.getTopic()
+ val message = stubMethod.messageAdapter.toMessage(topic, data)
+ stubMethod.argumentProcessor.inject(args)
return client.send(message, topic, stubMethod.qos)
}
@@ -50,9 +50,13 @@ internal class Coordinator(
)
val stream = flowable
- .map { it.message }
.observeOn(Schedulers.computation())
- .flatMap { message -> message.adapt(stubMethod.messageAdapter)?.let { Flowable.just(it) } ?: Flowable.empty() }
+ .flatMap { mqttMessage ->
+ mqttMessage.message.adapt(
+ mqttMessage.topic,
+ stubMethod.messageAdapter
+ )?.let { Flowable.just(it) } ?: Flowable.empty()
+ }
.toStream()
return stubMethod.streamAdapter.adapt(stream)
}
@@ -87,9 +91,13 @@ internal class Coordinator(
)
val stream = flowable
- .map { it.message }
.observeOn(Schedulers.computation())
- .flatMap { message -> message.adapt(stubMethod.messageAdapter)?.let { Flowable.just(it) } ?: Flowable.empty() }
+ .flatMap { mqttMessage ->
+ mqttMessage.message.adapt(
+ mqttMessage.topic,
+ stubMethod.messageAdapter
+ )?.let { Flowable.just(it) } ?: Flowable.empty()
+ }
.toStream()
return stubMethod.streamAdapter.adapt(stream)
}
@@ -113,9 +121,9 @@ internal class Coordinator(
}
}
- private fun Message.adapt(messageAdapter: MessageAdapter): T? {
+ private fun Message.adapt(topic: String, messageAdapter: MessageAdapter): T? {
return try {
- val message = messageAdapter.fromMessage(this)
+ val message = messageAdapter.fromMessage(topic, this)
logger.d("Coordinator", "Message after parsing: $message")
message
} catch (th: Throwable) {
diff --git a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/ByteArrayMessageAdapter.kt b/courier/src/main/java/com/gojek/courier/messageadapter/builtin/ByteArrayMessageAdapter.kt
index c41ef7af..10536091 100644
--- a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/ByteArrayMessageAdapter.kt
+++ b/courier/src/main/java/com/gojek/courier/messageadapter/builtin/ByteArrayMessageAdapter.kt
@@ -5,9 +5,11 @@ import com.gojek.courier.MessageAdapter
internal class ByteArrayMessageAdapter : MessageAdapter {
- override fun fromMessage(message: Message): ByteArray = when (message) {
+ override fun fromMessage(topic: String, message: Message): ByteArray = when (message) {
is Message.Bytes -> message.value
}
- override fun toMessage(data: ByteArray): Message = Message.Bytes(data)
+ override fun toMessage(topic: String, data: ByteArray): Message = Message.Bytes(data)
+
+ override fun contentType() = "application/octet-stream"
}
diff --git a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/TextMessageAdapter.kt b/courier/src/main/java/com/gojek/courier/messageadapter/builtin/TextMessageAdapter.kt
index 9cb44d47..5748f173 100644
--- a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/TextMessageAdapter.kt
+++ b/courier/src/main/java/com/gojek/courier/messageadapter/builtin/TextMessageAdapter.kt
@@ -5,9 +5,11 @@ import com.gojek.courier.MessageAdapter
internal class TextMessageAdapter : MessageAdapter {
- override fun fromMessage(message: Message): String = when (message) {
+ override fun fromMessage(topic: String, message: Message): String = when (message) {
is Message.Bytes -> String(message.value)
}
- override fun toMessage(data: String): Message = Message.Bytes(data.toByteArray())
+ override fun toMessage(topic: String, data: String): Message = Message.Bytes(data.toByteArray())
+
+ override fun contentType() = "text/plain"
}
From a227b3b3df6187289ffab0ac842c69a01d52bac1 Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Mon, 31 Oct 2022 10:52:20 +0530
Subject: [PATCH 07/25] Update documentation (#50)
---
docs/docs/MessageStreamAdapters.md | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/docs/docs/MessageStreamAdapters.md b/docs/docs/MessageStreamAdapters.md
index 3857e07a..0e9015c0 100644
--- a/docs/docs/MessageStreamAdapters.md
+++ b/docs/docs/MessageStreamAdapters.md
@@ -26,13 +26,17 @@ class MyCustomMessageAdapterFactory : MessageAdapter.Factory {
private class MyCustomMessageAdapter constructor() : MessageAdapter {
- override fun fromMessage(message: Message): T {
+ override fun fromMessage(topic: String, message: Message): T {
// convert message to custom type
}
- override fun toMessage(data: T): Message {
+ override fun toMessage(topic: String, data: T): Message {
// convert custom type to message
}
+
+ override fun contentType(): String {
+ // content-type supported by this adapter.
+ }
}
~~~
From f186dbda22b5829e43b6ccc38ee5e6d35ad62159 Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Mon, 14 Nov 2022 12:17:08 +0530
Subject: [PATCH 08/25] Remove built-in adapters and add text message adapter
(#51)
---
.github/workflows/publish.yml | 1 +
build.gradle.kts | 1 +
courier-message-adapter-text/.gitignore | 1 +
.../api/courier-message-adapter-text.api | 5 ++++
courier-message-adapter-text/build.gradle.kts | 28 +++++++++++++++++++
.../messageadapter/text/TextMessageAdapter.kt | 23 +++++++++++++++
.../messageadapter/text/ExampleUnitTest.kt | 16 +++++++++++
.../main/java/com/gojek/courier/Courier.kt | 6 ++--
.../builtin/BuiltInMessageAdapterFactory.kt | 14 ----------
.../builtin/ByteArrayMessageAdapter.kt | 15 ----------
.../builtin/TextMessageAdapter.kt | 15 ----------
.../builtin/BuiltInStreamAdapterFactory.kt | 14 ----------
.../builtin/IdentityStreamAdapter.kt | 9 ------
scripts/publishMavenLocal.sh | 2 +-
settings.gradle | 1 +
15 files changed, 79 insertions(+), 72 deletions(-)
create mode 100644 courier-message-adapter-text/.gitignore
create mode 100644 courier-message-adapter-text/api/courier-message-adapter-text.api
create mode 100644 courier-message-adapter-text/build.gradle.kts
create mode 100644 courier-message-adapter-text/src/main/java/com/gojek/courier/messageadapter/text/TextMessageAdapter.kt
create mode 100644 courier-message-adapter-text/src/test/java/com/gojek/courier/messageadapter/text/ExampleUnitTest.kt
delete mode 100644 courier/src/main/java/com/gojek/courier/messageadapter/builtin/BuiltInMessageAdapterFactory.kt
delete mode 100644 courier/src/main/java/com/gojek/courier/messageadapter/builtin/ByteArrayMessageAdapter.kt
delete mode 100644 courier/src/main/java/com/gojek/courier/messageadapter/builtin/TextMessageAdapter.kt
delete mode 100644 courier/src/main/java/com/gojek/courier/streamadapter/builtin/BuiltInStreamAdapterFactory.kt
delete mode 100644 courier/src/main/java/com/gojek/courier/streamadapter/builtin/IdentityStreamAdapter.kt
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 7c7e766e..2e813338 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -34,6 +34,7 @@ jobs:
:timer-pingsender:publishReleasePublicationToSonatypeRepository
:adaptive-keep-alive:publishReleasePublicationToSonatypeRepository
:network-tracker:publishReleasePublicationToSonatypeRepository
+ :courier-message-adapter-text:publishReleasePublicationToSonatypeRepository
:courier-message-adapter-gson:publishReleasePublicationToSonatypeRepository
:courier-message-adapter-moshi:publishReleasePublicationToSonatypeRepository
:courier-message-adapter-protobuf:publishReleasePublicationToSonatypeRepository
diff --git a/build.gradle.kts b/build.gradle.kts
index a3c80aa8..89c3dc31 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -56,6 +56,7 @@ val clean by tasks.creating(Delete::class) {
delete("${rootDir}/courier/build")
delete("${rootDir}/courier-core/build")
delete("${rootDir}/courier-core-android/build")
+ delete("${rootDir}/courier-message-adapter-text/build")
delete("${rootDir}/courier-message-adapter-gson/build")
delete("${rootDir}/courier-message-adapter-moshi/build")
delete("${rootDir}/courier-message-adapter-protobuf/build")
diff --git a/courier-message-adapter-text/.gitignore b/courier-message-adapter-text/.gitignore
new file mode 100644
index 00000000..796b96d1
--- /dev/null
+++ b/courier-message-adapter-text/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/courier-message-adapter-text/api/courier-message-adapter-text.api b/courier-message-adapter-text/api/courier-message-adapter-text.api
new file mode 100644
index 00000000..c902388d
--- /dev/null
+++ b/courier-message-adapter-text/api/courier-message-adapter-text.api
@@ -0,0 +1,5 @@
+public final class com/gojek/courier/messageadapter/text/TextMessageAdapterFactory : com/gojek/courier/MessageAdapter$Factory {
+ public fun ()V
+ public fun create (Ljava/lang/reflect/Type;[Ljava/lang/annotation/Annotation;)Lcom/gojek/courier/MessageAdapter;
+}
+
diff --git a/courier-message-adapter-text/build.gradle.kts b/courier-message-adapter-text/build.gradle.kts
new file mode 100644
index 00000000..16bc8532
--- /dev/null
+++ b/courier-message-adapter-text/build.gradle.kts
@@ -0,0 +1,28 @@
+import plugin.KotlinLibraryConfigurationPlugin
+
+apply()
+apply("$rootDir/gradle/script-ext.gradle")
+
+val version = ext.get("gitVersionName")
+
+ext {
+ set("PUBLISH_GROUP_ID", "com.gojek.courier")
+ set("PUBLISH_ARTIFACT_ID", "courier-message-adapter-text")
+ set("PUBLISH_VERSION", ext.get("gitVersionName"))
+ set("minimumCoverage", "0.0")
+}
+
+plugins {
+ id("java-library")
+ kotlin("jvm")
+ id(ScriptPlugins.apiValidator) version versions.apiValidator
+}
+
+dependencies {
+ api(project(":courier-core"))
+ implementation(deps.kotlin.stdlib.core)
+ implementation(deps.square.okio)
+ testImplementation(deps.android.test.kotlinTestJunit)
+}
+
+apply(from = "${rootProject.projectDir}/gradle/publish-module.gradle")
diff --git a/courier-message-adapter-text/src/main/java/com/gojek/courier/messageadapter/text/TextMessageAdapter.kt b/courier-message-adapter-text/src/main/java/com/gojek/courier/messageadapter/text/TextMessageAdapter.kt
new file mode 100644
index 00000000..eb20768a
--- /dev/null
+++ b/courier-message-adapter-text/src/main/java/com/gojek/courier/messageadapter/text/TextMessageAdapter.kt
@@ -0,0 +1,23 @@
+package com.gojek.courier.messageadapter.text
+
+import com.gojek.courier.Message
+import com.gojek.courier.MessageAdapter
+import com.gojek.courier.utils.getRawType
+import java.lang.reflect.Type
+
+class TextMessageAdapterFactory : MessageAdapter.Factory {
+ override fun create(type: Type, annotations: Array): MessageAdapter<*> = when (type.getRawType()) {
+ String::class.java -> TextMessageAdapter()
+ else -> throw IllegalArgumentException("Type is not supported by this MessageAdapterFactory: $type")
+ }
+}
+
+internal class TextMessageAdapter : MessageAdapter {
+ override fun fromMessage(topic: String, message: Message): String = when (message) {
+ is Message.Bytes -> String(message.value)
+ }
+
+ override fun toMessage(topic: String, data: String): Message = Message.Bytes(data.toByteArray())
+
+ override fun contentType() = "text/plain"
+}
diff --git a/courier-message-adapter-text/src/test/java/com/gojek/courier/messageadapter/text/ExampleUnitTest.kt b/courier-message-adapter-text/src/test/java/com/gojek/courier/messageadapter/text/ExampleUnitTest.kt
new file mode 100644
index 00000000..0fd4d3b7
--- /dev/null
+++ b/courier-message-adapter-text/src/test/java/com/gojek/courier/messageadapter/text/ExampleUnitTest.kt
@@ -0,0 +1,16 @@
+package com.gojek.courier.messageadapter.gson
+
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
diff --git a/courier/src/main/java/com/gojek/courier/Courier.kt b/courier/src/main/java/com/gojek/courier/Courier.kt
index bf11b215..5af24039 100644
--- a/courier/src/main/java/com/gojek/courier/Courier.kt
+++ b/courier/src/main/java/com/gojek/courier/Courier.kt
@@ -3,8 +3,6 @@ package com.gojek.courier
import com.gojek.courier.coordinator.Coordinator
import com.gojek.courier.logging.ILogger
import com.gojek.courier.logging.NoOpLogger
-import com.gojek.courier.messageadapter.builtin.BuiltInMessageAdapterFactory
-import com.gojek.courier.streamadapter.builtin.BuiltInStreamAdapterFactory
import com.gojek.courier.stub.ProxyFactory
import com.gojek.courier.stub.StubInterface
import com.gojek.courier.stub.StubMethod
@@ -52,10 +50,10 @@ class Courier(configuration: Configuration) {
)
private fun Configuration.createStreamAdapterResolver(): StreamAdapterResolver {
- return StreamAdapterResolver(listOf(BuiltInStreamAdapterFactory()) + streamAdapterFactories)
+ return StreamAdapterResolver(streamAdapterFactories)
}
private fun Configuration.createMessageAdapterResolver(): MessageAdapterResolver {
- return MessageAdapterResolver(listOf(BuiltInMessageAdapterFactory()) + messageAdapterFactories)
+ return MessageAdapterResolver(messageAdapterFactories)
}
}
diff --git a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/BuiltInMessageAdapterFactory.kt b/courier/src/main/java/com/gojek/courier/messageadapter/builtin/BuiltInMessageAdapterFactory.kt
deleted file mode 100644
index 674abf30..00000000
--- a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/BuiltInMessageAdapterFactory.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.gojek.courier.messageadapter.builtin
-
-import com.gojek.courier.MessageAdapter
-import com.gojek.courier.utils.getRawType
-import java.lang.reflect.Type
-
-internal class BuiltInMessageAdapterFactory : MessageAdapter.Factory {
-
- override fun create(type: Type, annotations: Array): MessageAdapter<*> = when (type.getRawType()) {
- String::class.java -> TextMessageAdapter()
- ByteArray::class.java -> ByteArrayMessageAdapter()
- else -> throw IllegalArgumentException("Type is not supported by this MessageAdapterFactory: $type")
- }
-}
diff --git a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/ByteArrayMessageAdapter.kt b/courier/src/main/java/com/gojek/courier/messageadapter/builtin/ByteArrayMessageAdapter.kt
deleted file mode 100644
index 10536091..00000000
--- a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/ByteArrayMessageAdapter.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.gojek.courier.messageadapter.builtin
-
-import com.gojek.courier.Message
-import com.gojek.courier.MessageAdapter
-
-internal class ByteArrayMessageAdapter : MessageAdapter {
-
- override fun fromMessage(topic: String, message: Message): ByteArray = when (message) {
- is Message.Bytes -> message.value
- }
-
- override fun toMessage(topic: String, data: ByteArray): Message = Message.Bytes(data)
-
- override fun contentType() = "application/octet-stream"
-}
diff --git a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/TextMessageAdapter.kt b/courier/src/main/java/com/gojek/courier/messageadapter/builtin/TextMessageAdapter.kt
deleted file mode 100644
index 5748f173..00000000
--- a/courier/src/main/java/com/gojek/courier/messageadapter/builtin/TextMessageAdapter.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.gojek.courier.messageadapter.builtin
-
-import com.gojek.courier.Message
-import com.gojek.courier.MessageAdapter
-
-internal class TextMessageAdapter : MessageAdapter {
-
- override fun fromMessage(topic: String, message: Message): String = when (message) {
- is Message.Bytes -> String(message.value)
- }
-
- override fun toMessage(topic: String, data: String): Message = Message.Bytes(data.toByteArray())
-
- override fun contentType() = "text/plain"
-}
diff --git a/courier/src/main/java/com/gojek/courier/streamadapter/builtin/BuiltInStreamAdapterFactory.kt b/courier/src/main/java/com/gojek/courier/streamadapter/builtin/BuiltInStreamAdapterFactory.kt
deleted file mode 100644
index 503bf8d9..00000000
--- a/courier/src/main/java/com/gojek/courier/streamadapter/builtin/BuiltInStreamAdapterFactory.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.gojek.courier.streamadapter.builtin
-
-import com.gojek.courier.Stream
-import com.gojek.courier.StreamAdapter
-import com.gojek.courier.utils.getRawType
-import java.lang.reflect.Type
-
-internal class BuiltInStreamAdapterFactory : StreamAdapter.Factory {
-
- override fun create(type: Type): StreamAdapter = when (type.getRawType()) {
- Stream::class.java -> IdentityStreamAdapter()
- else -> throw IllegalArgumentException("$type is not supported.")
- }
-}
diff --git a/courier/src/main/java/com/gojek/courier/streamadapter/builtin/IdentityStreamAdapter.kt b/courier/src/main/java/com/gojek/courier/streamadapter/builtin/IdentityStreamAdapter.kt
deleted file mode 100644
index bb2551ee..00000000
--- a/courier/src/main/java/com/gojek/courier/streamadapter/builtin/IdentityStreamAdapter.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.gojek.courier.streamadapter.builtin
-
-import com.gojek.courier.Stream
-import com.gojek.courier.StreamAdapter
-
-internal class IdentityStreamAdapter : StreamAdapter> {
-
- override fun adapt(stream: Stream): Stream = stream
-}
diff --git a/scripts/publishMavenLocal.sh b/scripts/publishMavenLocal.sh
index 661d826b..0803a611 100755
--- a/scripts/publishMavenLocal.sh
+++ b/scripts/publishMavenLocal.sh
@@ -4,7 +4,7 @@ echo "Publishing Libraries to Maven Local..."
./gradlew :paho:assemble :courier-core:assemble :courier-core-android:assemble --parallel --daemon && ./gradlew :paho:publishToMavenLocal -PIS_LOCAL=true :courier-core:publishToMavenLocal -PIS_LOCAL=true :courier-core-android:publishToMavenLocal -PIS_LOCAL=true --parallel --daemon
./gradlew :mqtt-pingsender:assemble && ./gradlew :mqtt-pingsender:publishToMavenLocal -PIS_LOCAL=true
./gradlew :workmanager-pingsender:assemble :workmanager-2.6.0-pingsender:assemble :alarm-pingsender:assemble :timer-pingsender:assemble --parallel --daemon && ./gradlew :workmanager-pingsender:publishToMavenLocal -PIS_LOCAL=true :workmanager-2.6.0-pingsender:publishToMavenLocal -PIS_LOCAL=true :alarm-pingsender:publishToMavenLocal -PIS_LOCAL=true :timer-pingsender:publishToMavenLocal -PIS_LOCAL=true --parallel --daemon
-./gradlew :network-tracker:assemble :adaptive-keep-alive:assemble :courier-message-adapter-gson:assemble :courier-message-adapter-protobuf:assemble :courier-message-adapter-moshi:assemble :courier-stream-adapter-rxjava:assemble :courier-stream-adapter-rxjava2:assemble :courier-stream-adapter-coroutines:assemble :courier:assemble :app-state-manager:assemble --parallel --daemon && ./gradlew :network-tracker:publishToMavenLocal -PIS_LOCAL=true :adaptive-keep-alive:publishToMavenLocal -PIS_LOCAL=true :courier-message-adapter-gson:publishToMavenLocal -PIS_LOCAL=true :courier-message-adapter-moshi:publishToMavenLocal -PIS_LOCAL=true :courier-message-adapter-protobuf:publishToMavenLocal -PIS_LOCAL=true :courier-stream-adapter-rxjava:publishToMavenLocal -PIS_LOCAL=true :courier-stream-adapter-rxjava2:publishToMavenLocal -PIS_LOCAL=true :courier-stream-adapter-coroutines:publishToMavenLocal -PIS_LOCAL=true :courier:publishToMavenLocal -PIS_LOCAL=true :app-state-manager:publishToMavenLocal -PIS_LOCAL=true --parallel --daemon
+./gradlew :network-tracker:assemble :adaptive-keep-alive:assemble :courier-message-adapter-gson:assemble :courier-message-adapter-text:assemble :courier-message-adapter-protobuf:assemble :courier-message-adapter-moshi:assemble :courier-stream-adapter-rxjava:assemble :courier-stream-adapter-rxjava2:assemble :courier-stream-adapter-coroutines:assemble :courier:assemble :app-state-manager:assemble --parallel --daemon && ./gradlew :network-tracker:publishToMavenLocal -PIS_LOCAL=true :adaptive-keep-alive:publishToMavenLocal -PIS_LOCAL=true :courier-message-adapter-gson:publishToMavenLocal -PIS_LOCAL=true :courier-message-adapter-text:publishToMavenLocal -PIS_LOCAL=true :courier-message-adapter-moshi:publishToMavenLocal -PIS_LOCAL=true :courier-message-adapter-protobuf:publishToMavenLocal -PIS_LOCAL=true :courier-stream-adapter-rxjava:publishToMavenLocal -PIS_LOCAL=true :courier-stream-adapter-rxjava2:publishToMavenLocal -PIS_LOCAL=true :courier-stream-adapter-coroutines:publishToMavenLocal -PIS_LOCAL=true :courier:publishToMavenLocal -PIS_LOCAL=true :app-state-manager:publishToMavenLocal -PIS_LOCAL=true --parallel --daemon
./gradlew :mqtt-client:assemble --parallel --daemon && ./gradlew :mqtt-client:publishToMavenLocal -PIS_LOCAL=true --parallel --daemon
./gradlew :courier:assemble :courier-auth-http:assemble --parallel --daemon && ./gradlew :courier:publishToMavenLocal -PIS_LOCAL=true :courier-auth-http:publishToMavenLocal -PIS_LOCAL=true --parallel --daemon
./gradlew :chuck-mqtt:assemble :chuck-mqtt-no-ops:assembleRelease --parallel --daemon && ./gradlew :chuck-mqtt:publishToMavenLocal -PIS_LOCAL=true :chuck-mqtt-no-ops:publishToMavenLocal -PIS_LOCAL=true --parallel --daemon
diff --git a/settings.gradle b/settings.gradle
index bfc495c8..535bc28f 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -5,6 +5,7 @@ include ':mqtt-client'
include ':courier'
include ':courier-core'
include ':courier-core-android'
+include ':courier-message-adapter-text'
include ':courier-message-adapter-gson'
include ':courier-message-adapter-moshi'
include ':courier-message-adapter-protobuf'
From df1403fde9aba961c7427be23577466e1afd564a Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Fri, 18 Nov 2022 09:15:14 +0530
Subject: [PATCH 09/25] Fix argument injection in topic name (#52)
---
.../src/main/java/com/gojek/courier/coordinator/Coordinator.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
index a4f7253a..3d54e6d8 100644
--- a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
+++ b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
@@ -23,9 +23,9 @@ internal class Coordinator(
@Synchronized
override fun send(stubMethod: StubMethod.Send, args: Array): Any {
val data = stubMethod.argumentProcessor.getDataArgument(args)
+ stubMethod.argumentProcessor.inject(args)
val topic = stubMethod.argumentProcessor.getTopic()
val message = stubMethod.messageAdapter.toMessage(topic, data)
- stubMethod.argumentProcessor.inject(args)
return client.send(message, topic, stubMethod.qos)
}
From ef5f5df43a449a7afc21da6d0988afd0cf051b15 Mon Sep 17 00:00:00 2001
From: Anubhav Gupta
Date: Fri, 2 Dec 2022 23:22:24 +0530
Subject: [PATCH 10/25] only set alpn protocol if protocol list is not empty
(#53)
---
.../internal/platform/android/AndroidSocketAdapter.kt | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt
index f51ef808..ce02a4f5 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt
@@ -59,10 +59,12 @@ open class AndroidSocketAdapter(private val sslSocketClass: Class)
}
// Enable ALPN.
- setAlpnProtocols.invoke(
- sslSocket,
- Platform.concatLengthPrefixed(protocols)
- )
+ if (protocols.isNotEmpty()) {
+ setAlpnProtocols.invoke(
+ sslSocket,
+ Platform.concatLengthPrefixed(protocols)
+ )
+ }
} catch (e: IllegalAccessException) {
throw AssertionError(e)
} catch (e: InvocationTargetException) {
From 97216660e8d225b0007668fc3a8df8d0e14c1b02 Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Fri, 3 Mar 2023 17:14:56 +0530
Subject: [PATCH 11/25] Add api for adding/removing event handler dynamically
(#56)
* Add api for adding/removing event handler dynamically
* Add API to get event stream via Courier
* Add API to get connection state via Courier
---
.../com/gojek/courier/app/ui/MainActivity.kt | 2 +-
courier/api/courier.api | 2 +
.../main/java/com/gojek/courier/Courier.kt | 10 ++++
.../gojek/courier/coordinator/Coordinator.kt | 52 +++++++++++++++++++
.../com/gojek/courier/stub/StubInterface.kt | 5 ++
mqtt-client/api/mqtt-client.api | 23 ++++----
.../java/com/gojek/mqtt/client/MqttClient.kt | 3 ++
.../gojek/mqtt/client/MqttCourierClient.kt | 9 ++++
.../mqtt/client/config/MqttConfiguration.kt | 2 -
.../client/config/v3/MqttV3Configuration.kt | 4 --
...entsInterceptor.kt => MqttEventHandler.kt} | 13 ++++-
.../factory/IAndroidMqttClientFactory.kt | 13 +++--
.../client/internal/MqttClientInternal.kt | 13 ++++-
.../mqtt/client/v3/impl/AndroidMqttClient.kt | 34 ++++++------
14 files changed, 139 insertions(+), 46 deletions(-)
rename mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/{MqttEventsInterceptor.kt => MqttEventHandler.kt} (62%)
diff --git a/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt b/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt
index 83a821c5..40c344a4 100644
--- a/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt
+++ b/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt
@@ -107,7 +107,6 @@ class MainActivity : AppCompatActivity() {
private fun initialiseCourier() {
val mqttConfig = MqttV3Configuration(
logger = getLogger(),
- eventHandler = eventHandler,
authenticator = object : Authenticator {
override fun authenticate(
connectOptions: MqttConnectOptions,
@@ -136,6 +135,7 @@ class MainActivity : AppCompatActivity() {
pingSender = WorkPingSenderFactory.createMqttPingSender(applicationContext, WorkManagerPingSenderConfig())
)
mqttClient = MqttClientFactory.create(this, mqttConfig)
+ mqttClient.addEventHandler(eventHandler)
val configuration = Courier.Configuration(
client = mqttClient,
diff --git a/courier/api/courier.api b/courier/api/courier.api
index acc81f5d..d7d5ed12 100644
--- a/courier/api/courier.api
+++ b/courier/api/courier.api
@@ -1,6 +1,8 @@
public final class com/gojek/courier/Courier {
public fun (Lcom/gojek/courier/Courier$Configuration;)V
public final fun create (Ljava/lang/Class;)Ljava/lang/Object;
+ public final fun getConnectionState ()Lcom/gojek/mqtt/client/model/ConnectionState;
+ public final fun getEventStream ()Lcom/gojek/courier/Stream;
}
public final class com/gojek/courier/Courier$Configuration {
diff --git a/courier/src/main/java/com/gojek/courier/Courier.kt b/courier/src/main/java/com/gojek/courier/Courier.kt
index 5af24039..5b74fa36 100644
--- a/courier/src/main/java/com/gojek/courier/Courier.kt
+++ b/courier/src/main/java/com/gojek/courier/Courier.kt
@@ -10,6 +10,8 @@ import com.gojek.courier.utils.MessageAdapterResolver
import com.gojek.courier.utils.RuntimePlatform
import com.gojek.courier.utils.StreamAdapterResolver
import com.gojek.mqtt.client.MqttClient
+import com.gojek.mqtt.client.model.ConnectionState
+import com.gojek.mqtt.event.MqttEvent
class Courier(configuration: Configuration) {
private val stubInterfaceFactory: StubInterface.Factory
@@ -42,6 +44,14 @@ class Courier(configuration: Configuration) {
*/
inline fun create(): T = create(T::class.java)
+ fun getEventStream(): Stream {
+ return coordinator.getEventStream()
+ }
+
+ fun getConnectionState(): ConnectionState {
+ return coordinator.getConnectionState()
+ }
+
data class Configuration(
val client: MqttClient,
val streamAdapterFactories: List = emptyList(),
diff --git a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
index 3d54e6d8..0b298076 100644
--- a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
+++ b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
@@ -3,17 +3,24 @@ package com.gojek.courier.coordinator
import com.gojek.courier.Message
import com.gojek.courier.MessageAdapter
import com.gojek.courier.QoS
+import com.gojek.courier.Stream
+import com.gojek.courier.Stream.Disposable
+import com.gojek.courier.Stream.Observer
import com.gojek.courier.logging.ILogger
import com.gojek.courier.stub.StubInterface
import com.gojek.courier.stub.StubMethod
import com.gojek.courier.utils.toStream
import com.gojek.mqtt.client.MqttClient
import com.gojek.mqtt.client.listener.MessageListener
+import com.gojek.mqtt.client.model.ConnectionState
import com.gojek.mqtt.client.model.MqttMessage
+import com.gojek.mqtt.event.EventHandler
+import com.gojek.mqtt.event.MqttEvent
import io.reactivex.BackpressureStrategy
import io.reactivex.Flowable
import io.reactivex.FlowableOnSubscribe
import io.reactivex.schedulers.Schedulers
+import org.reactivestreams.Subscriber
internal class Coordinator(
private val client: MqttClient,
@@ -121,6 +128,51 @@ internal class Coordinator(
}
}
+ override fun getEventStream(): Stream {
+ return object : Stream {
+ override fun start(observer: Observer): Disposable {
+ val eventHandler = object : EventHandler {
+ override fun onEvent(mqttEvent: MqttEvent) {
+ try {
+ observer.onNext(mqttEvent)
+ } catch (throwable: Throwable) {
+ observer.onError(throwable)
+ }
+ }
+ }
+ client.addEventHandler(eventHandler)
+ var isDisposed = false
+ return object : Disposable {
+ override fun dispose() {
+ client.removeEventHandler(eventHandler)
+ isDisposed = true
+ }
+
+ override fun isDisposed(): Boolean {
+ return isDisposed
+ }
+ }
+ }
+
+ override fun subscribe(s: Subscriber) {
+ val eventHandler = object : EventHandler {
+ override fun onEvent(mqttEvent: MqttEvent) {
+ try {
+ s.onNext(mqttEvent)
+ } catch (throwable: Throwable) {
+ s.onError(throwable)
+ }
+ }
+ }
+ client.addEventHandler(eventHandler)
+ }
+ }
+ }
+
+ override fun getConnectionState(): ConnectionState {
+ return client.getCurrentState()
+ }
+
private fun Message.adapt(topic: String, messageAdapter: MessageAdapter): T? {
return try {
val message = messageAdapter.fromMessage(topic, this)
diff --git a/courier/src/main/java/com/gojek/courier/stub/StubInterface.kt b/courier/src/main/java/com/gojek/courier/stub/StubInterface.kt
index d4ca1c9d..a5a85261 100644
--- a/courier/src/main/java/com/gojek/courier/stub/StubInterface.kt
+++ b/courier/src/main/java/com/gojek/courier/stub/StubInterface.kt
@@ -1,6 +1,9 @@
package com.gojek.courier.stub
+import com.gojek.courier.Stream
import com.gojek.courier.utils.RuntimePlatform
+import com.gojek.mqtt.client.model.ConnectionState
+import com.gojek.mqtt.event.MqttEvent
import java.lang.reflect.Method
internal class StubInterface(
@@ -38,6 +41,8 @@ internal class StubInterface(
fun subscribeWithStream(stubMethod: StubMethod.SubscribeWithStream, args: Array): Any
fun unsubscribe(stubMethod: StubMethod.Unsubscribe, args: Array): Any
fun subscribeAll(stubMethod: StubMethod.SubscribeAll, args: Array): Any
+ fun getEventStream(): Stream
+ fun getConnectionState(): ConnectionState
}
internal class Factory(
diff --git a/mqtt-client/api/mqtt-client.api b/mqtt-client/api/mqtt-client.api
index fcbcf07a..acf9fa4c 100644
--- a/mqtt-client/api/mqtt-client.api
+++ b/mqtt-client/api/mqtt-client.api
@@ -3,12 +3,14 @@ public abstract interface class com/gojek/mqtt/auth/Authenticator {
}
public abstract interface class com/gojek/mqtt/client/MqttClient {
+ public abstract fun addEventHandler (Lcom/gojek/mqtt/event/EventHandler;)V
public abstract fun addGlobalMessageListener (Lcom/gojek/mqtt/client/listener/MessageListener;)V
public abstract fun addMessageListener (Ljava/lang/String;Lcom/gojek/mqtt/client/listener/MessageListener;)V
public abstract fun connect (Lcom/gojek/mqtt/model/MqttConnectOptions;)V
public abstract fun disconnect (Z)V
public abstract fun getCurrentState ()Lcom/gojek/mqtt/client/model/ConnectionState;
public abstract fun reconnect ()V
+ public abstract fun removeEventHandler (Lcom/gojek/mqtt/event/EventHandler;)V
public abstract fun removeMessageListener (Ljava/lang/String;Lcom/gojek/mqtt/client/listener/MessageListener;)V
public abstract fun send (Lcom/gojek/courier/Message;Ljava/lang/String;Lcom/gojek/courier/QoS;)Z
public abstract fun subscribe (Lkotlin/Pair;[Lkotlin/Pair;)V
@@ -52,12 +54,11 @@ public final class com/gojek/mqtt/client/config/ExperimentConfigs {
}
public abstract class com/gojek/mqtt/client/config/MqttConfiguration {
- public fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)V
+ public fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)V
public fun getAuthFailureHandler ()Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;
public fun getAuthenticator ()Lcom/gojek/mqtt/auth/Authenticator;
public fun getConnectRetryTimePolicy ()Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;
public fun getConnectTimeoutPolicy ()Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;
- public fun getEventHandler ()Lcom/gojek/mqtt/event/EventHandler;
public fun getExperimentConfigs ()Lcom/gojek/mqtt/client/config/ExperimentConfigs;
public fun getLogger ()Lcom/gojek/courier/logging/ILogger;
public fun getMqttInterceptorList ()Ljava/util/List;
@@ -95,13 +96,12 @@ public final class com/gojek/mqtt/client/config/SubscriptionStore : java/lang/En
}
public final class com/gojek/mqtt/client/config/v3/MqttV3Configuration : com/gojek/mqtt/client/config/MqttConfiguration {
- public fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)V
- public synthetic fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)V
+ public synthetic fun (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;
- public final fun component10 ()Lcom/gojek/mqtt/pingsender/MqttPingSender;
- public final fun component11 ()Ljava/util/List;
- public final fun component12 ()Lcom/gojek/mqtt/client/config/PersistenceOptions;
- public final fun component13 ()Lcom/gojek/mqtt/client/config/ExperimentConfigs;
+ public final fun component10 ()Ljava/util/List;
+ public final fun component11 ()Lcom/gojek/mqtt/client/config/PersistenceOptions;
+ public final fun component12 ()Lcom/gojek/mqtt/client/config/ExperimentConfigs;
public final fun component2 ()Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;
public final fun component3 ()Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;
public final fun component4 ()Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;
@@ -109,15 +109,14 @@ public final class com/gojek/mqtt/client/config/v3/MqttV3Configuration : com/goj
public final fun component6 ()Lcom/gojek/courier/logging/ILogger;
public final fun component7 ()Lcom/gojek/mqtt/auth/Authenticator;
public final fun component8 ()Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;
- public final fun component9 ()Lcom/gojek/mqtt/event/EventHandler;
- public final fun copy (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/event/EventHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;ILjava/lang/Object;)Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;
+ public final fun component9 ()Lcom/gojek/mqtt/pingsender/MqttPingSender;
+ public final fun copy (Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;)Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;Lcom/gojek/mqtt/policies/subscriptionretry/ISubscriptionRetryPolicy;ILcom/gojek/courier/logging/ILogger;Lcom/gojek/mqtt/auth/Authenticator;Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;Lcom/gojek/mqtt/pingsender/MqttPingSender;Ljava/util/List;Lcom/gojek/mqtt/client/config/PersistenceOptions;Lcom/gojek/mqtt/client/config/ExperimentConfigs;ILjava/lang/Object;)Lcom/gojek/mqtt/client/config/v3/MqttV3Configuration;
public fun equals (Ljava/lang/Object;)Z
public fun getAuthFailureHandler ()Lcom/gojek/mqtt/exception/handler/v3/AuthFailureHandler;
public fun getAuthenticator ()Lcom/gojek/mqtt/auth/Authenticator;
public fun getConnectRetryTimePolicy ()Lcom/gojek/mqtt/policies/connectretrytime/IConnectRetryTimePolicy;
public fun getConnectTimeoutPolicy ()Lcom/gojek/mqtt/policies/connecttimeout/IConnectTimeoutPolicy;
- public fun getEventHandler ()Lcom/gojek/mqtt/event/EventHandler;
public fun getExperimentConfigs ()Lcom/gojek/mqtt/client/config/ExperimentConfigs;
public fun getLogger ()Lcom/gojek/courier/logging/ILogger;
public fun getMqttInterceptorList ()Ljava/util/List;
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttClient.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttClient.kt
index 5a47a919..2aadb27f 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttClient.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttClient.kt
@@ -4,6 +4,7 @@ import com.gojek.courier.Message
import com.gojek.courier.QoS
import com.gojek.mqtt.client.listener.MessageListener
import com.gojek.mqtt.client.model.ConnectionState
+import com.gojek.mqtt.event.EventHandler
import com.gojek.mqtt.model.MqttConnectOptions
interface MqttClient {
@@ -17,4 +18,6 @@ interface MqttClient {
fun addMessageListener(topic: String, listener: MessageListener)
fun removeMessageListener(topic: String, listener: MessageListener)
fun addGlobalMessageListener(listener: MessageListener)
+ fun addEventHandler(eventHandler: EventHandler)
+ fun removeEventHandler(eventHandler: EventHandler)
}
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttCourierClient.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttCourierClient.kt
index c75df2b4..a0643119 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttCourierClient.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/MqttCourierClient.kt
@@ -5,6 +5,7 @@ import com.gojek.courier.QoS
import com.gojek.mqtt.client.internal.MqttClientInternal
import com.gojek.mqtt.client.listener.MessageListener
import com.gojek.mqtt.client.model.ConnectionState
+import com.gojek.mqtt.event.EventHandler
import com.gojek.mqtt.model.MqttConnectOptions
import com.gojek.mqtt.model.MqttPacket
@@ -50,4 +51,12 @@ internal class MqttCourierClient(
override fun addGlobalMessageListener(listener: MessageListener) {
mqttClient.addGlobalMessageListener(listener)
}
+
+ override fun addEventHandler(eventHandler: EventHandler) {
+ mqttClient.addEventHandler(eventHandler)
+ }
+
+ override fun removeEventHandler(eventHandler: EventHandler) {
+ mqttClient.removeEventHandler(eventHandler)
+ }
}
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/MqttConfiguration.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/MqttConfiguration.kt
index 0a6c3f6b..26e83a36 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/MqttConfiguration.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/MqttConfiguration.kt
@@ -3,7 +3,6 @@ package com.gojek.mqtt.client.config
import com.gojek.courier.logging.ILogger
import com.gojek.mqtt.auth.Authenticator
import com.gojek.mqtt.client.MqttInterceptor
-import com.gojek.mqtt.event.EventHandler
import com.gojek.mqtt.exception.handler.v3.AuthFailureHandler
import com.gojek.mqtt.pingsender.MqttPingSender
import com.gojek.mqtt.policies.connectretrytime.IConnectRetryTimePolicy
@@ -19,7 +18,6 @@ abstract class MqttConfiguration(
open val logger: ILogger,
open val authenticator: Authenticator,
open val authFailureHandler: AuthFailureHandler?,
- open val eventHandler: EventHandler,
open val pingSender: MqttPingSender,
open val mqttInterceptorList: List,
open val persistenceOptions: PersistenceOptions,
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/v3/MqttV3Configuration.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/v3/MqttV3Configuration.kt
index 39dd9c2a..475d9914 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/v3/MqttV3Configuration.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/v3/MqttV3Configuration.kt
@@ -9,8 +9,6 @@ import com.gojek.mqtt.client.config.MqttConfiguration
import com.gojek.mqtt.client.config.PersistenceOptions
import com.gojek.mqtt.client.config.PersistenceOptions.PahoPersistenceOptions
import com.gojek.mqtt.constants.DEFAULT_WAKELOCK_TIMEOUT
-import com.gojek.mqtt.event.EventHandler
-import com.gojek.mqtt.event.NoOpEventHandler
import com.gojek.mqtt.exception.handler.v3.AuthFailureHandler
import com.gojek.mqtt.pingsender.MqttPingSender
import com.gojek.mqtt.policies.connectretrytime.ConnectRetryTimeConfig
@@ -36,7 +34,6 @@ data class MqttV3Configuration(
override val logger: ILogger = NoOpLogger(),
override val authenticator: Authenticator,
override val authFailureHandler: AuthFailureHandler? = null,
- override val eventHandler: EventHandler = NoOpEventHandler(),
override val pingSender: MqttPingSender,
override val mqttInterceptorList: List = emptyList(),
override val persistenceOptions: PersistenceOptions = PahoPersistenceOptions(),
@@ -50,7 +47,6 @@ data class MqttV3Configuration(
logger = logger,
authenticator = authenticator,
authFailureHandler = authFailureHandler,
- eventHandler = eventHandler,
pingSender = pingSender,
mqttInterceptorList = mqttInterceptorList,
persistenceOptions = persistenceOptions,
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventsInterceptor.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventHandler.kt
similarity index 62%
rename from mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventsInterceptor.kt
rename to mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventHandler.kt
index 42bb9455..fdb70f31 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventsInterceptor.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventHandler.kt
@@ -4,9 +4,10 @@ import com.gojek.mqtt.event.EventHandler
import com.gojek.mqtt.event.MqttEvent
import java.util.concurrent.CopyOnWriteArrayList
-internal class MqttEventsInterceptor(private val eventHandler: EventHandler) : EventHandler {
+internal class MqttEventHandler : EventHandler {
private val interceptorList = CopyOnWriteArrayList()
+ private val eventHandlers = CopyOnWriteArrayList()
init {
interceptorList.add(ConnectionInfoInterceptor())
@@ -17,7 +18,15 @@ internal class MqttEventsInterceptor(private val eventHandler: EventHandler) : E
interceptorList.forEach {
event = it.intercept(event)
}
- eventHandler.onEvent(event)
+ eventHandlers.forEach { it.onEvent(mqttEvent) }
+ }
+
+ fun addEventHandler(handler: EventHandler) {
+ eventHandlers.add(handler)
+ }
+
+ fun removeEventHandler(handler: EventHandler) {
+ eventHandlers.remove(handler)
}
fun addInterceptor(interceptor: EventInterceptor) {
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/factory/IAndroidMqttClientFactory.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/factory/IAndroidMqttClientFactory.kt
index ba61a07f..bc54b154 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/factory/IAndroidMqttClientFactory.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/factory/IAndroidMqttClientFactory.kt
@@ -48,13 +48,12 @@ internal class AndroidMqttClientFactory : IAndroidMqttClientFactory {
pingSender.setPingEventHandler(pingEventHandler)
return AndroidMqttClient(
context = context,
- mqttConfiguration = mqttConfiguration.copy(
- eventHandler = eventHandler
- ),
+ mqttConfiguration = mqttConfiguration,
networkStateTracker = networkStateTracker,
mqttPingSender = pingSender,
keepAliveProvider = keepAliveProvider,
- keepAliveFailureHandler = keepAliveFailureHandler
+ keepAliveFailureHandler = keepAliveFailureHandler,
+ eventHandler = eventHandler
)
}
@@ -71,14 +70,14 @@ internal class AndroidMqttClientFactory : IAndroidMqttClientFactory {
return AndroidMqttClient(
context = context,
mqttConfiguration = mqttConfiguration.copy(
- logger = NoOpLogger(),
- eventHandler = NoOpEventHandler()
+ logger = NoOpLogger()
),
networkStateTracker = networkStateTracker,
mqttPingSender = pingSender,
isAdaptiveKAConnection = true,
keepAliveProvider = keepAliveProvider,
- keepAliveFailureHandler = keepAliveFailureHandler
+ keepAliveFailureHandler = keepAliveFailureHandler,
+ eventHandler = NoOpEventHandler()
)
}
}
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/internal/MqttClientInternal.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/internal/MqttClientInternal.kt
index 8d5dbec0..ea2259b2 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/internal/MqttClientInternal.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/internal/MqttClientInternal.kt
@@ -9,12 +9,13 @@ import com.gojek.keepalive.OptimalKeepAliveObserver
import com.gojek.keepalive.OptimalKeepAliveProvider
import com.gojek.keepalive.config.AdaptiveKeepAliveConfig as AdaptiveKAConfig
import com.gojek.mqtt.client.config.v3.MqttV3Configuration
-import com.gojek.mqtt.client.event.interceptor.MqttEventsInterceptor
+import com.gojek.mqtt.client.event.interceptor.MqttEventHandler
import com.gojek.mqtt.client.factory.getAndroidMqttClientFactory
import com.gojek.mqtt.client.listener.MessageListener
import com.gojek.mqtt.client.model.ConnectionState
import com.gojek.mqtt.client.v3.IAndroidMqttClient
import com.gojek.mqtt.event.AdaptivePingEventHandler
+import com.gojek.mqtt.event.EventHandler
import com.gojek.mqtt.event.MqttEvent.OptimalKeepAliveFoundEvent
import com.gojek.mqtt.event.PingEventHandler
import com.gojek.mqtt.model.AdaptiveKeepAliveConfig
@@ -40,7 +41,7 @@ internal class MqttClientInternal(
private var keepAliveProvider: KeepAliveProvider = NonAdaptiveKeepAliveProvider()
private var keepAliveFailureHandler: KeepAliveFailureHandler = NoOpKeepAliveFailureHandler()
- private val eventHandler = MqttEventsInterceptor(mqttConfiguration.eventHandler)
+ private val eventHandler = MqttEventHandler()
private val optimalKeepAliveObserver = object : OptimalKeepAliveObserver {
override fun onOptimalKeepAliveFound(
@@ -166,4 +167,12 @@ internal class MqttClientInternal(
)
}
}
+
+ fun addEventHandler(eventHandler: EventHandler) {
+ this.eventHandler.addEventHandler(eventHandler)
+ }
+
+ fun removeEventHandler(eventHandler: EventHandler) {
+ this.eventHandler.removeEventHandler(eventHandler)
+ }
}
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
index 757403f8..65209a5f 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
@@ -43,6 +43,7 @@ import com.gojek.mqtt.connection.config.v3.ConnectionConfig
import com.gojek.mqtt.constants.MAX_INFLIGHT_MESSAGES_ALLOWED
import com.gojek.mqtt.constants.MESSAGE
import com.gojek.mqtt.constants.MSG_APP_PUBLISH
+import com.gojek.mqtt.event.EventHandler
import com.gojek.mqtt.event.MqttEvent.AuthenticatorErrorEvent
import com.gojek.mqtt.event.MqttEvent.MqttConnectDiscardedEvent
import com.gojek.mqtt.event.MqttEvent.MqttConnectFailureEvent
@@ -88,6 +89,7 @@ internal class AndroidMqttClient(
private val mqttPingSender: MqttPingSender,
private val isAdaptiveKAConnection: Boolean = false,
private val keepAliveProvider: KeepAliveProvider,
+ private val eventHandler: EventHandler,
keepAliveFailureHandler: KeepAliveFailureHandler
) : IAndroidMqttClient, IClientSchedulerBridge {
@@ -144,7 +146,7 @@ internal class AndroidMqttClient(
mqttThreadHandler,
this,
logger,
- mqttConfiguration.eventHandler,
+ eventHandler,
experimentConfigs.activityCheckIntervalSeconds
)
mqttUtils = MqttUtils()
@@ -158,7 +160,7 @@ internal class AndroidMqttClient(
networkStateTracker = networkStateTracker
)
mqttClientEventAdapter = MqttClientEventAdapter(
- eventHandler = mqttConfiguration.eventHandler,
+ eventHandler = eventHandler,
networkHandler = networkHandler
)
val connectionConfig =
@@ -198,7 +200,7 @@ internal class AndroidMqttClient(
mqttUtils,
mqttPersistence,
logger,
- mqttConfiguration.eventHandler,
+ eventHandler,
experimentConfigs.incomingMessagesTTLSecs,
experimentConfigs.incomingMessagesCleanupIntervalSecs,
clock
@@ -217,7 +219,7 @@ internal class AndroidMqttClient(
// This can be invoked on any thread
override fun reconnect() {
- mqttConfiguration.eventHandler.onEvent(MqttReconnectEvent())
+ eventHandler.onEvent(MqttReconnectEvent())
runnableScheduler.disconnectMqtt(true)
}
@@ -245,14 +247,14 @@ internal class AndroidMqttClient(
"with qos ${mqttPacket.qos}"
)
with(mqttPacket) {
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttMessageSendEvent(topic, qos, message.size)
)
}
mqttConnection.publish(mqttPacket, mqttPacket.qos, mqttPacket.topic)
} catch (e: MqttPersistenceException) {
with(mqttPacket) {
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttMessageSendFailureEvent(
topic = topic,
qos = qos,
@@ -263,7 +265,7 @@ internal class AndroidMqttClient(
}
} catch (e: MqttException) {
with(mqttPacket) {
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttMessageSendFailureEvent(
topic = topic,
qos = qos,
@@ -276,7 +278,7 @@ internal class AndroidMqttClient(
} catch (e: java.lang.Exception) {
// this might happen if mqtt object becomes null while disconnect, so just ignore
with(mqttPacket) {
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttMessageSendFailureEvent(
topic = topic,
qos = qos,
@@ -337,7 +339,7 @@ internal class AndroidMqttClient(
logger.d(TAG, "Sending onConnectAttempt event")
if (!isInitialised) {
logger.d(TAG, "Mqtt Client not initialised")
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttConnectDiscardedEvent(
"Mqtt Client not initialised",
networkHandler.getActiveNetworkInfo()
@@ -368,7 +370,7 @@ internal class AndroidMqttClient(
} catch (e: AuthApiException) /* this exception can be thrown by authenticator */ {
logger.e(TAG, "Auth exception : ${e.message}")
forceRefresh = true
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
AuthenticatorErrorEvent(
exception = e.toCourierException(),
nextRetryTimeSecs = e.nextRetrySeconds,
@@ -384,7 +386,7 @@ internal class AndroidMqttClient(
}
} catch (e: Exception) /* this exception cannot be thrown on connect */ {
logger.e(TAG, "Connect exception : ${e.message}")
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttConnectFailureEvent(
exception = e.toCourierException(),
activeNetInfo = networkHandler.getActiveNetworkInfo(),
@@ -399,7 +401,7 @@ internal class AndroidMqttClient(
// This runs on Mqtt thread
override fun disconnectMqtt(clearState: Boolean) {
- mqttConfiguration.eventHandler.onEvent(MqttDisconnectEvent())
+ eventHandler.onEvent(MqttDisconnectEvent())
mqttConnection.disconnect()
if (clearState) {
mqttConnection.shutDown()
@@ -537,7 +539,7 @@ internal class AndroidMqttClient(
IMessageReceiveListener {
override fun messageArrived(topic: String, byteArray: ByteArray): Boolean {
try {
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttMessageReceiveEvent(topic, byteArray.size)
)
val bytes = mqttUtils.uncompressByteArray(byteArray)!!
@@ -555,14 +557,14 @@ internal class AndroidMqttClient(
globalListener?.onMessageReceived(mqttPacket.toMqttMessage())
triggerHandleMessage()
} catch (e: IllegalStateException) {
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttMessageReceiveErrorEvent(topic, byteArray.size, e.toCourierException())
)
logger.e(TAG, "Exception when msg arrived : ", e)
runnableScheduler.disconnectMqtt(true)
return false
} catch (e: Throwable) {
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttMessageReceiveErrorEvent(topic, byteArray.size, e.toCourierException())
)
logger.e(TAG, "Exception when msg arrived : ", e)
@@ -575,7 +577,7 @@ internal class AndroidMqttClient(
IMessageSendListener {
override fun onSuccess(packet: MqttSendPacket) {
with(packet) {
- mqttConfiguration.eventHandler.onEvent(
+ eventHandler.onEvent(
MqttMessageSendSuccessEvent(
topic,
qos,
From 48db728e320884649f6990cab1e18d9a9a93ff17 Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Fri, 10 Mar 2023 12:00:07 +0530
Subject: [PATCH 12/25] Add new builder functionality in Courier (#57)
* Add new builder functionality in Courier
---
courier/api/courier.api | 8 ++++++
.../main/java/com/gojek/courier/Courier.kt | 27 ++++++++++++++++++-
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/courier/api/courier.api b/courier/api/courier.api
index d7d5ed12..825a2dca 100644
--- a/courier/api/courier.api
+++ b/courier/api/courier.api
@@ -3,6 +3,14 @@ public final class com/gojek/courier/Courier {
public final fun create (Ljava/lang/Class;)Ljava/lang/Object;
public final fun getConnectionState ()Lcom/gojek/mqtt/client/model/ConnectionState;
public final fun getEventStream ()Lcom/gojek/courier/Stream;
+ public final fun newBuilder ()Lcom/gojek/courier/Courier$Builder;
+}
+
+public final class com/gojek/courier/Courier$Builder {
+ public fun (Lcom/gojek/courier/Courier$Configuration;)V
+ public final fun addMessageAdapterFactories (Ljava/util/List;)Lcom/gojek/courier/Courier$Builder;
+ public final fun addStreamAdapterFactories (Ljava/util/List;)Lcom/gojek/courier/Courier$Builder;
+ public final fun build ()Lcom/gojek/courier/Courier;
}
public final class com/gojek/courier/Courier$Configuration {
diff --git a/courier/src/main/java/com/gojek/courier/Courier.kt b/courier/src/main/java/com/gojek/courier/Courier.kt
index 5b74fa36..4e39cd71 100644
--- a/courier/src/main/java/com/gojek/courier/Courier.kt
+++ b/courier/src/main/java/com/gojek/courier/Courier.kt
@@ -13,7 +13,7 @@ import com.gojek.mqtt.client.MqttClient
import com.gojek.mqtt.client.model.ConnectionState
import com.gojek.mqtt.event.MqttEvent
-class Courier(configuration: Configuration) {
+class Courier(private val configuration: Configuration) {
private val stubInterfaceFactory: StubInterface.Factory
private val proxyFactory: ProxyFactory
private val coordinator: Coordinator
@@ -52,6 +52,10 @@ class Courier(configuration: Configuration) {
return coordinator.getConnectionState()
}
+ fun newBuilder(): Builder {
+ return Builder(configuration)
+ }
+
data class Configuration(
val client: MqttClient,
val streamAdapterFactories: List = emptyList(),
@@ -66,4 +70,25 @@ class Courier(configuration: Configuration) {
private fun Configuration.createMessageAdapterResolver(): MessageAdapterResolver {
return MessageAdapterResolver(messageAdapterFactories)
}
+
+ class Builder(private var configuration: Configuration) {
+
+ fun addMessageAdapterFactories(messageAdapterFactories: List): Builder {
+ configuration = configuration.copy(
+ messageAdapterFactories = messageAdapterFactories + configuration.messageAdapterFactories
+ )
+ return this
+ }
+
+ fun addStreamAdapterFactories(streamAdapterFactories: List): Builder {
+ configuration = configuration.copy(
+ streamAdapterFactories = streamAdapterFactories + configuration.streamAdapterFactories
+ )
+ return this
+ }
+
+ fun build(): Courier {
+ return Courier(configuration)
+ }
+ }
}
From d98980c17f88110415813f88a3c8921e98eabbf2 Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Thu, 23 Mar 2023 11:04:56 +0530
Subject: [PATCH 13/25] Fix event stream buffer overflow issue (#60)
---
.../java/com/gojek/courier/coordinator/Coordinator.kt | 11 ++++++++++-
.../mqtt/client/event/interceptor/MqttEventHandler.kt | 4 ++--
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
index 0b298076..c93a085f 100644
--- a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
+++ b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
@@ -21,6 +21,7 @@ import io.reactivex.Flowable
import io.reactivex.FlowableOnSubscribe
import io.reactivex.schedulers.Schedulers
import org.reactivestreams.Subscriber
+import org.reactivestreams.Subscription
internal class Coordinator(
private val client: MqttClient,
@@ -164,7 +165,15 @@ internal class Coordinator(
}
}
}
- client.addEventHandler(eventHandler)
+ s.onSubscribe(object : Subscription {
+ override fun request(n: Long) {
+ client.addEventHandler(eventHandler)
+ }
+
+ override fun cancel() {
+ client.removeEventHandler(eventHandler)
+ }
+ })
}
}
}
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventHandler.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventHandler.kt
index fdb70f31..028c5cd0 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventHandler.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/event/interceptor/MqttEventHandler.kt
@@ -22,7 +22,7 @@ internal class MqttEventHandler : EventHandler {
}
fun addEventHandler(handler: EventHandler) {
- eventHandlers.add(handler)
+ eventHandlers.addIfAbsent(handler)
}
fun removeEventHandler(handler: EventHandler) {
@@ -30,6 +30,6 @@ internal class MqttEventHandler : EventHandler {
}
fun addInterceptor(interceptor: EventInterceptor) {
- interceptorList.add(interceptor)
+ interceptorList.addIfAbsent(interceptor)
}
}
From d53d2639be31dfb4fef6e20a377935521325ab98 Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Wed, 29 Mar 2023 13:11:17 +0530
Subject: [PATCH 14/25] Fix ordering of message & stream adapter factories
(#61)
---
courier/src/main/java/com/gojek/courier/Courier.kt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/courier/src/main/java/com/gojek/courier/Courier.kt b/courier/src/main/java/com/gojek/courier/Courier.kt
index 4e39cd71..40a978b1 100644
--- a/courier/src/main/java/com/gojek/courier/Courier.kt
+++ b/courier/src/main/java/com/gojek/courier/Courier.kt
@@ -75,14 +75,14 @@ class Courier(private val configuration: Configuration) {
fun addMessageAdapterFactories(messageAdapterFactories: List): Builder {
configuration = configuration.copy(
- messageAdapterFactories = messageAdapterFactories + configuration.messageAdapterFactories
+ messageAdapterFactories = configuration.messageAdapterFactories + messageAdapterFactories
)
return this
}
fun addStreamAdapterFactories(streamAdapterFactories: List): Builder {
configuration = configuration.copy(
- streamAdapterFactories = streamAdapterFactories + configuration.streamAdapterFactories
+ streamAdapterFactories = configuration.streamAdapterFactories + streamAdapterFactories
)
return this
}
From 42a90aa6b4d389bc8a0bde255de1818f22f190e0 Mon Sep 17 00:00:00 2001
From: ChandoraAnkit
Date: Thu, 30 Mar 2023 22:13:46 +0530
Subject: [PATCH 15/25] Fix formatting issue
---
.../presentation/mapper/MqttTransactionUiModelMapper.kt | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt b/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt
index 292de1c2..2ee31cf9 100644
--- a/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt
+++ b/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt
@@ -24,7 +24,8 @@ import `in`.mohalla.paho.client.mqttv3.internal.wire.MqttUnsubAck
import `in`.mohalla.paho.client.mqttv3.internal.wire.MqttUnsubscribe
import `in`.mohalla.paho.client.mqttv3.internal.wire.MqttWireMessage
-internal class MqttTransactionUiModelMapper : Mapper {
+internal class MqttTransactionUiModelMapper :
+ Mapper {
override fun map(input: MqttTransactionDomainModel): MqttTransactionUiModel {
return with(input) {
MqttTransactionUiModel(
@@ -161,7 +162,8 @@ internal class MqttTransactionUiModelMapper : Mapper {
formatBody(String(mqttWireMessage.message.payload, UTF_8))
- } else -> ""
+ }
+ else -> ""
}
}
From e66ea5ec0f512aa072c4fa86d4dcd6fe1aaa1b13 Mon Sep 17 00:00:00 2001
From: ChandoraAnkit
Date: Thu, 30 Mar 2023 22:21:24 +0530
Subject: [PATCH 16/25] Fix formatting issue
---
.../presentation/mapper/MqttTransactionUiModelMapper.kt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt b/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt
index 2ee31cf9..090258f1 100644
--- a/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt
+++ b/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt
@@ -5,8 +5,6 @@ import com.gojek.chuckmqtt.internal.domain.model.MqttTransactionDomainModel
import com.gojek.chuckmqtt.internal.presentation.model.MqttTransactionUiModel
import com.gojek.chuckmqtt.internal.utils.formatBody
import com.gojek.chuckmqtt.internal.utils.formatByteCount
-import java.text.DateFormat
-import kotlin.text.Charsets.UTF_8
import `in`.mohalla.paho.client.mqttv3.MqttMessage
import `in`.mohalla.paho.client.mqttv3.internal.wire.MqttConnack
import `in`.mohalla.paho.client.mqttv3.internal.wire.MqttConnect
@@ -23,6 +21,8 @@ import `in`.mohalla.paho.client.mqttv3.internal.wire.MqttSubscribe
import `in`.mohalla.paho.client.mqttv3.internal.wire.MqttUnsubAck
import `in`.mohalla.paho.client.mqttv3.internal.wire.MqttUnsubscribe
import `in`.mohalla.paho.client.mqttv3.internal.wire.MqttWireMessage
+import java.text.DateFormat
+import kotlin.text.Charsets.UTF_8
internal class MqttTransactionUiModelMapper :
Mapper {
From 4e6309dee959a1c2f238ec94d84ab4cd872ace4d Mon Sep 17 00:00:00 2001
From: ChandoraAnkit
Date: Thu, 30 Mar 2023 22:33:37 +0530
Subject: [PATCH 17/25] Fix formatting issue
---
.../gojek/mqtt/client/v3/impl/AndroidMqttClient.kt | 4 ++--
.../handler/v3/impl/MqttExceptionHandlerImpl.kt | 2 +-
.../gojek/mqtt/persistence/impl/PahoPersistence.kt | 4 ++--
.../handler/v3/impl/MqttExceptionHandlerImplTest.kt | 12 ++++++------
4 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
index ff22d04c..afac607e 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
@@ -76,11 +76,11 @@ import com.gojek.mqtt.utils.MqttUtils
import com.gojek.mqtt.utils.NetworkUtils
import com.gojek.mqtt.wakelock.WakeLockProvider
import com.gojek.networktracker.NetworkStateTracker
-import java.nio.charset.StandardCharsets
-import java.util.concurrent.TimeUnit
import `in`.mohalla.paho.client.mqttv3.MqttException
import `in`.mohalla.paho.client.mqttv3.MqttException.REASON_CODE_UNEXPECTED_ERROR
import `in`.mohalla.paho.client.mqttv3.MqttPersistenceException
+import java.nio.charset.StandardCharsets
+import java.util.concurrent.TimeUnit
internal class AndroidMqttClient(
private val context: Context,
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImpl.kt b/mqtt-client/src/main/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImpl.kt
index 305ae0a7..988f51bd 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImpl.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImpl.kt
@@ -5,13 +5,13 @@ import com.gojek.mqtt.constants.SERVER_UNAVAILABLE_MAX_CONNECT_TIME
import com.gojek.mqtt.exception.handler.v3.MqttExceptionHandler
import com.gojek.mqtt.policies.connectretrytime.IConnectRetryTimePolicy
import com.gojek.mqtt.scheduler.IRunnableScheduler
+import `in`.mohalla.paho.client.mqttv3.MqttException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.nio.channels.UnresolvedAddressException
import java.util.Random
import javax.net.ssl.SSLHandshakeException
-import `in`.mohalla.paho.client.mqttv3.MqttException
internal class MqttExceptionHandlerImpl(
private val runnableScheduler: IRunnableScheduler,
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/persistence/impl/PahoPersistence.kt b/mqtt-client/src/main/java/com/gojek/mqtt/persistence/impl/PahoPersistence.kt
index 27a23c15..e4981649 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/persistence/impl/PahoPersistence.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/persistence/impl/PahoPersistence.kt
@@ -8,11 +8,11 @@ import com.gojek.mqtt.persistence.dao.PahoMessagesDao
import com.gojek.mqtt.persistence.db.MqttDatabase
import com.gojek.mqtt.persistence.model.MqttPahoPacket
import com.gojek.mqtt.persistence.model.MqttReceivePacket
-import java.util.Collections
-import java.util.Enumeration
import `in`.mohalla.paho.client.mqttv3.MqttClientPersistence
import `in`.mohalla.paho.client.mqttv3.MqttPersistable
import `in`.mohalla.paho.client.mqttv3.internal.MqttPersistentData
+import java.util.Collections
+import java.util.Enumeration
internal class PahoPersistence(private val context: Context) :
MqttClientPersistence, IMqttReceivePersistence {
diff --git a/mqtt-client/src/test/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImplTest.kt b/mqtt-client/src/test/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImplTest.kt
index e0599f5c..b6af64e7 100644
--- a/mqtt-client/src/test/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImplTest.kt
+++ b/mqtt-client/src/test/java/com/gojek/mqtt/exception/handler/v3/impl/MqttExceptionHandlerImplTest.kt
@@ -7,12 +7,6 @@ import com.gojek.mqtt.scheduler.IRunnableScheduler
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
-import java.net.SocketException
-import java.net.SocketTimeoutException
-import java.net.UnknownHostException
-import java.nio.channels.UnresolvedAddressException
-import java.util.Random
-import javax.net.ssl.SSLHandshakeException
import `in`.mohalla.paho.client.mqttv3.MqttException
import `in`.mohalla.paho.client.mqttv3.MqttException.REASON_CODE_BROKER_UNAVAILABLE
import `in`.mohalla.paho.client.mqttv3.MqttException.REASON_CODE_CLIENT_ALREADY_DISCONNECTED
@@ -37,6 +31,12 @@ import `in`.mohalla.paho.client.mqttv3.MqttException.REASON_CODE_SOCKET_FACTORY_
import `in`.mohalla.paho.client.mqttv3.MqttException.REASON_CODE_SSL_CONFIG_ERROR
import `in`.mohalla.paho.client.mqttv3.MqttException.REASON_CODE_TOKEN_INUSE
import `in`.mohalla.paho.client.mqttv3.MqttException.REASON_CODE_UNEXPECTED_ERROR
+import java.net.SocketException
+import java.net.SocketTimeoutException
+import java.net.UnknownHostException
+import java.nio.channels.UnresolvedAddressException
+import java.util.Random
+import javax.net.ssl.SSLHandshakeException
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.verifyNoInteractions
From 561c5a6b27608e37c230b9bff360bff1bf213ccf Mon Sep 17 00:00:00 2001
From: ChandoraAnkit
Date: Thu, 30 Mar 2023 22:43:53 +0530
Subject: [PATCH 18/25] Fix formatting issue
---
.../gojek/mqtt/model/MqttConnectOptions.kt | 6 +++---
.../hostfallback/HostFallbackPolicyTest.kt | 2 +-
.../paho/client/mqttv3/ConnectionSpec.kt | 6 +++---
.../internal/platform/Android10Platform.kt | 6 +++---
.../internal/platform/AndroidPlatform.kt | 20 +++++++++----------
.../internal/platform/BouncyCastlePlatform.kt | 2 +-
.../internal/platform/ConscryptPlatform.kt | 2 +-
.../platform/Jdk8WithJettyBootPlatform.kt | 2 +-
.../mqttv3/internal/platform/Jdk9Platform.kt | 4 ++--
.../internal/platform/OpenJSSEPlatform.kt | 2 +-
.../mqttv3/internal/platform/Platform.kt | 12 +++++------
.../android/Android10SocketAdapter.kt | 4 ++--
.../android/AndroidCertificateChainCleaner.kt | 4 ++--
.../platform/android/AndroidSocketAdapter.kt | 6 +++---
.../android/BouncyCastleSocketAdapter.kt | 4 ++--
.../android/ConscryptSocketAdapter.kt | 4 ++--
.../platform/android/DeferredSocketAdapter.kt | 2 +-
.../platform/android/SocketAdapter.kt | 2 +-
.../android/StandardAndroidSocketAdapter.kt | 4 ++--
.../internal/tls/CertificateChainCleaner.kt | 2 +-
.../gojek/timer/pingsender/TimerPingSender.kt | 4 ++--
.../timer/pingsender/TimerPingSenderTest.kt | 8 ++++----
.../WorkManagerPingSenderAdaptiveTest.kt | 8 ++++----
.../pingsender/WorkManagerPingSenderTest.kt | 8 ++++----
.../WorkManagerPingSenderAdaptiveTest.kt | 8 ++++----
.../pingsender/WorkManagerPingSenderTest.kt | 8 ++++----
26 files changed, 70 insertions(+), 70 deletions(-)
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt b/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
index 043e84ab..2a453e24 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/model/MqttConnectOptions.kt
@@ -2,12 +2,12 @@ package com.gojek.mqtt.model
import com.gojek.mqtt.model.KeepAlive.Companion.NO_KEEP_ALIVE
import com.gojek.mqtt.model.MqttVersion.VERSION_3_1_1
-import javax.net.SocketFactory
-import javax.net.ssl.SSLSocketFactory
-import javax.net.ssl.X509TrustManager
import `in`.mohalla.paho.client.mqttv3.ConnectionSpec
import `in`.mohalla.paho.client.mqttv3.Protocol
import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform
+import javax.net.SocketFactory
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
class MqttConnectOptions private constructor(
builder: Builder
diff --git a/mqtt-client/src/test/java/com/gojek/mqtt/policies/hostfallback/HostFallbackPolicyTest.kt b/mqtt-client/src/test/java/com/gojek/mqtt/policies/hostfallback/HostFallbackPolicyTest.kt
index cd2ed3ee..82bf366d 100644
--- a/mqtt-client/src/test/java/com/gojek/mqtt/policies/hostfallback/HostFallbackPolicyTest.kt
+++ b/mqtt-client/src/test/java/com/gojek/mqtt/policies/hostfallback/HostFallbackPolicyTest.kt
@@ -1,8 +1,8 @@
package com.gojek.mqtt.policies.hostfallback
import com.gojek.mqtt.model.ServerUri
-import java.lang.IllegalArgumentException
import `in`.mohalla.paho.client.mqttv3.MqttException
+import java.lang.IllegalArgumentException
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/ConnectionSpec.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/ConnectionSpec.kt
index 63e4f2da..36ddae50 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/ConnectionSpec.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/ConnectionSpec.kt
@@ -15,12 +15,12 @@
*/
package `in`.mohalla.paho.client.mqttv3
-import java.util.Arrays
-import java.util.Objects
-import javax.net.ssl.SSLSocket
import `in`.mohalla.paho.client.mqttv3.ConnectionSpec.Builder
import `in`.mohalla.paho.client.mqttv3.internal.tls.CipherSuite
import `in`.mohalla.paho.client.mqttv3.internal.tls.TlsVersion
+import java.util.Arrays
+import java.util.Objects
+import javax.net.ssl.SSLSocket
/**
* Specifies configuration for the socket connection that HTTP traffic travels through. For `https:`
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Android10Platform.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Android10Platform.kt
index 9fad3e89..b48928eb 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Android10Platform.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Android10Platform.kt
@@ -19,9 +19,6 @@ import android.annotation.SuppressLint
import android.os.Build
import android.security.NetworkSecurityPolicy
import android.util.CloseGuard
-import javax.net.ssl.SSLSocket
-import javax.net.ssl.SSLSocketFactory
-import javax.net.ssl.X509TrustManager
import `in`.mohalla.paho.client.mqttv3.Protocol
import `in`.mohalla.paho.client.mqttv3.SuppressSignatureCheck
import `in`.mohalla.paho.client.mqttv3.internal.platform.android.Android10SocketAdapter
@@ -31,6 +28,9 @@ import `in`.mohalla.paho.client.mqttv3.internal.platform.android.BouncyCastleSoc
import `in`.mohalla.paho.client.mqttv3.internal.platform.android.ConscryptSocketAdapter
import `in`.mohalla.paho.client.mqttv3.internal.platform.android.DeferredSocketAdapter
import `in`.mohalla.paho.client.mqttv3.internal.tls.CertificateChainCleaner
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
/** Android 29+. */
@SuppressSignatureCheck
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/AndroidPlatform.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/AndroidPlatform.kt
index 08b71a47..86512470 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/AndroidPlatform.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/AndroidPlatform.kt
@@ -17,16 +17,6 @@ package `in`.mohalla.paho.client.mqttv3.internal.platform
import android.os.Build
import android.security.NetworkSecurityPolicy
-import java.io.IOException
-import java.lang.reflect.InvocationTargetException
-import java.lang.reflect.Method
-import java.net.InetSocketAddress
-import java.net.Socket
-import java.security.cert.TrustAnchor
-import java.security.cert.X509Certificate
-import javax.net.ssl.SSLSocket
-import javax.net.ssl.SSLSocketFactory
-import javax.net.ssl.X509TrustManager
import `in`.mohalla.paho.client.mqttv3.Protocol
import `in`.mohalla.paho.client.mqttv3.SuppressSignatureCheck
import `in`.mohalla.paho.client.mqttv3.internal.platform.android.AndroidCertificateChainCleaner
@@ -37,6 +27,16 @@ import `in`.mohalla.paho.client.mqttv3.internal.platform.android.DeferredSocketA
import `in`.mohalla.paho.client.mqttv3.internal.platform.android.StandardAndroidSocketAdapter
import `in`.mohalla.paho.client.mqttv3.internal.tls.CertificateChainCleaner
import `in`.mohalla.paho.client.mqttv3.internal.tls.TrustRootIndex
+import java.io.IOException
+import java.lang.reflect.InvocationTargetException
+import java.lang.reflect.Method
+import java.net.InetSocketAddress
+import java.net.Socket
+import java.security.cert.TrustAnchor
+import java.security.cert.X509Certificate
+import javax.net.ssl.SSLSocket
+import javax.net.ssl.SSLSocketFactory
+import javax.net.ssl.X509TrustManager
/** Android 5+. */
@SuppressSignatureCheck
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/BouncyCastlePlatform.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/BouncyCastlePlatform.kt
index f5b6d137..f4c8e541 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/BouncyCastlePlatform.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/BouncyCastlePlatform.kt
@@ -15,6 +15,7 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform
+import `in`.mohalla.paho.client.mqttv3.Protocol
import java.security.KeyStore
import java.security.Provider
import javax.net.ssl.SSLContext
@@ -24,7 +25,6 @@ import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import org.bouncycastle.jsse.BCSSLSocket
import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-import `in`.mohalla.paho.client.mqttv3.Protocol
/**
* Platform using BouncyCastle if installed as the first Security Provider.
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/ConscryptPlatform.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/ConscryptPlatform.kt
index eb792e12..92580b16 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/ConscryptPlatform.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/ConscryptPlatform.kt
@@ -15,6 +15,7 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform
+import `in`.mohalla.paho.client.mqttv3.Protocol
import java.security.KeyStore
import java.security.Provider
import java.security.cert.X509Certificate
@@ -27,7 +28,6 @@ import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import org.conscrypt.Conscrypt
import org.conscrypt.ConscryptHostnameVerifier
-import `in`.mohalla.paho.client.mqttv3.Protocol
/**
* Platform using Conscrypt (conscrypt.org) if installed as the first Security Provider.
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Jdk8WithJettyBootPlatform.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Jdk8WithJettyBootPlatform.kt
index 9bbf192f..1df58949 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Jdk8WithJettyBootPlatform.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Jdk8WithJettyBootPlatform.kt
@@ -15,12 +15,12 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform
+import `in`.mohalla.paho.client.mqttv3.Protocol
import java.lang.reflect.InvocationHandler
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
import java.lang.reflect.Proxy
import javax.net.ssl.SSLSocket
-import `in`.mohalla.paho.client.mqttv3.Protocol
/** OpenJDK 8 with `org.mortbay.jetty.alpn:alpn-boot` in the boot class path. */
class Jdk8WithJettyBootPlatform(
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Jdk9Platform.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Jdk9Platform.kt
index 421726f4..2f1ba467 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Jdk9Platform.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Jdk9Platform.kt
@@ -15,13 +15,13 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform
+import `in`.mohalla.paho.client.mqttv3.Protocol
+import `in`.mohalla.paho.client.mqttv3.SuppressSignatureCheck
import java.security.NoSuchAlgorithmException
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager
-import `in`.mohalla.paho.client.mqttv3.Protocol
-import `in`.mohalla.paho.client.mqttv3.SuppressSignatureCheck
/** OpenJDK 9+. */
open class Jdk9Platform : Platform() {
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/OpenJSSEPlatform.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/OpenJSSEPlatform.kt
index ee795a65..ebf1f59c 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/OpenJSSEPlatform.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/OpenJSSEPlatform.kt
@@ -15,6 +15,7 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform
+import `in`.mohalla.paho.client.mqttv3.Protocol
import java.security.KeyStore
import java.security.Provider
import javax.net.ssl.SSLContext
@@ -22,7 +23,6 @@ import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
-import `in`.mohalla.paho.client.mqttv3.Protocol
/**
* Platform using OpenJSSE (https://github.com/openjsse/openjsse) if installed as the first
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Platform.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Platform.kt
index 99af275f..ed285d81 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Platform.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/Platform.kt
@@ -16,6 +16,12 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform
+import `in`.mohalla.paho.client.mqttv3.Protocol
+import `in`.mohalla.paho.client.mqttv3.internal.tls.BasicCertificateChainCleaner
+import `in`.mohalla.paho.client.mqttv3.internal.tls.BasicTrustRootIndex
+import `in`.mohalla.paho.client.mqttv3.internal.tls.CertificateChainCleaner
+import `in`.mohalla.paho.client.mqttv3.internal.tls.TrustRootIndex
+import `in`.mohalla.paho.client.mqttv3.readFieldOrNull
import java.io.IOException
import java.net.InetSocketAddress
import java.net.Socket
@@ -31,12 +37,6 @@ import javax.net.ssl.TrustManager
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import okio.Buffer
-import `in`.mohalla.paho.client.mqttv3.Protocol
-import `in`.mohalla.paho.client.mqttv3.internal.tls.BasicCertificateChainCleaner
-import `in`.mohalla.paho.client.mqttv3.internal.tls.BasicTrustRootIndex
-import `in`.mohalla.paho.client.mqttv3.internal.tls.CertificateChainCleaner
-import `in`.mohalla.paho.client.mqttv3.internal.tls.TrustRootIndex
-import `in`.mohalla.paho.client.mqttv3.readFieldOrNull
/**
* Access to platform-specific features.
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/Android10SocketAdapter.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/Android10SocketAdapter.kt
index 2be18362..22b1c3e8 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/Android10SocketAdapter.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/Android10SocketAdapter.kt
@@ -18,12 +18,12 @@ package `in`.mohalla.paho.client.mqttv3.internal.platform.android
import android.annotation.SuppressLint
import android.net.ssl.SSLSockets
import android.os.Build
-import java.io.IOException
-import javax.net.ssl.SSLSocket
import `in`.mohalla.paho.client.mqttv3.Protocol
import `in`.mohalla.paho.client.mqttv3.SuppressSignatureCheck
import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform
import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform.Companion.isAndroid
+import java.io.IOException
+import javax.net.ssl.SSLSocket
/**
* Simple non-reflection SocketAdapter for Android Q+.
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/AndroidCertificateChainCleaner.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/AndroidCertificateChainCleaner.kt
index 14f94a7d..f7f1759f 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/AndroidCertificateChainCleaner.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/AndroidCertificateChainCleaner.kt
@@ -16,13 +16,13 @@
package `in`.mohalla.paho.client.mqttv3.internal.platform.android
import android.net.http.X509TrustManagerExtensions
+import `in`.mohalla.paho.client.mqttv3.SuppressSignatureCheck
+import `in`.mohalla.paho.client.mqttv3.internal.tls.CertificateChainCleaner
import java.security.cert.Certificate
import java.security.cert.CertificateException
import java.security.cert.X509Certificate
import javax.net.ssl.SSLPeerUnverifiedException
import javax.net.ssl.X509TrustManager
-import `in`.mohalla.paho.client.mqttv3.SuppressSignatureCheck
-import `in`.mohalla.paho.client.mqttv3.internal.tls.CertificateChainCleaner
/**
* Android implementation of CertificateChainCleaner using direct Android API calls.
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt
index 2b7c4bda..20881154 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/AndroidSocketAdapter.kt
@@ -15,13 +15,13 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform.android
-import java.lang.reflect.InvocationTargetException
-import java.lang.reflect.Method
-import javax.net.ssl.SSLSocket
import `in`.mohalla.paho.client.mqttv3.Protocol
import `in`.mohalla.paho.client.mqttv3.internal.platform.AndroidPlatform
import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform
import `in`.mohalla.paho.client.mqttv3.internal.platform.android.DeferredSocketAdapter.Factory
+import java.lang.reflect.InvocationTargetException
+import java.lang.reflect.Method
+import javax.net.ssl.SSLSocket
/**
* Modern reflection based SocketAdapter for Conscrypt class SSLSockets.
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/BouncyCastleSocketAdapter.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/BouncyCastleSocketAdapter.kt
index 0ea18009..98c57083 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/BouncyCastleSocketAdapter.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/BouncyCastleSocketAdapter.kt
@@ -15,12 +15,12 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform.android
-import javax.net.ssl.SSLSocket
-import org.bouncycastle.jsse.BCSSLSocket
import `in`.mohalla.paho.client.mqttv3.Protocol
import `in`.mohalla.paho.client.mqttv3.internal.platform.BouncyCastlePlatform
import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform
import `in`.mohalla.paho.client.mqttv3.internal.platform.android.DeferredSocketAdapter.Factory
+import javax.net.ssl.SSLSocket
+import org.bouncycastle.jsse.BCSSLSocket
/**
* Simple non-reflection SocketAdapter for BouncyCastle.
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/ConscryptSocketAdapter.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/ConscryptSocketAdapter.kt
index 80cac921..31beee52 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/ConscryptSocketAdapter.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/ConscryptSocketAdapter.kt
@@ -15,12 +15,12 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform.android
-import javax.net.ssl.SSLSocket
-import org.conscrypt.Conscrypt
import `in`.mohalla.paho.client.mqttv3.Protocol
import `in`.mohalla.paho.client.mqttv3.internal.platform.ConscryptPlatform
import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform
import `in`.mohalla.paho.client.mqttv3.internal.platform.android.DeferredSocketAdapter.Factory
+import javax.net.ssl.SSLSocket
+import org.conscrypt.Conscrypt
/**
* Simple non-reflection SocketAdapter for Conscrypt when included as an application dependency
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/DeferredSocketAdapter.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/DeferredSocketAdapter.kt
index b9518b88..79d493c1 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/DeferredSocketAdapter.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/DeferredSocketAdapter.kt
@@ -15,8 +15,8 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform.android
-import javax.net.ssl.SSLSocket
import `in`.mohalla.paho.client.mqttv3.Protocol
+import javax.net.ssl.SSLSocket
/**
* Deferred implementation of SocketAdapter that works by observing the socket
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/SocketAdapter.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/SocketAdapter.kt
index cd97fa12..6ac47f9c 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/SocketAdapter.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/SocketAdapter.kt
@@ -15,10 +15,10 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform.android
+import `in`.mohalla.paho.client.mqttv3.Protocol
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager
-import `in`.mohalla.paho.client.mqttv3.Protocol
interface SocketAdapter {
fun isSupported(): Boolean
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/StandardAndroidSocketAdapter.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/StandardAndroidSocketAdapter.kt
index 1b54af05..8f26eadd 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/StandardAndroidSocketAdapter.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/platform/android/StandardAndroidSocketAdapter.kt
@@ -15,11 +15,11 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.platform.android
+import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform
+import `in`.mohalla.paho.client.mqttv3.readFieldOrNull
import javax.net.ssl.SSLSocket
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.X509TrustManager
-import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform
-import `in`.mohalla.paho.client.mqttv3.readFieldOrNull
/**
* Base Android reflection based SocketAdapter for the built in Android SSLSocket.
diff --git a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/tls/CertificateChainCleaner.kt b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/tls/CertificateChainCleaner.kt
index f70b3825..db7f9430 100644
--- a/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/tls/CertificateChainCleaner.kt
+++ b/paho/src/main/java/in/mohalla/paho/client/mqttv3/internal/tls/CertificateChainCleaner.kt
@@ -16,11 +16,11 @@
*/
package `in`.mohalla.paho.client.mqttv3.internal.tls
+import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform
import java.security.cert.Certificate
import java.security.cert.X509Certificate
import javax.net.ssl.SSLPeerUnverifiedException
import javax.net.ssl.X509TrustManager
-import `in`.mohalla.paho.client.mqttv3.internal.platform.Platform
/**
* Computes the effective certificate chain from the raw array returned by Java's built in TLS APIs.
diff --git a/pingsender/timer-pingsender/src/main/java/com/gojek/timer/pingsender/TimerPingSender.kt b/pingsender/timer-pingsender/src/main/java/com/gojek/timer/pingsender/TimerPingSender.kt
index 4a1d804d..04e14fa9 100644
--- a/pingsender/timer-pingsender/src/main/java/com/gojek/timer/pingsender/TimerPingSender.kt
+++ b/pingsender/timer-pingsender/src/main/java/com/gojek/timer/pingsender/TimerPingSender.kt
@@ -7,12 +7,12 @@ import com.gojek.courier.utils.Clock
import com.gojek.mqtt.pingsender.IPingSenderEvents
import com.gojek.mqtt.pingsender.MqttPingSender
import com.gojek.mqtt.pingsender.NoOpPingSenderEvents
-import java.util.Timer
-import java.util.TimerTask
import `in`.mohalla.paho.client.mqttv3.ILogger
import `in`.mohalla.paho.client.mqttv3.IMqttActionListener
import `in`.mohalla.paho.client.mqttv3.IMqttToken
import `in`.mohalla.paho.client.mqttv3.internal.ClientComms
+import java.util.Timer
+import java.util.TimerTask
/**
* Default ping sender implementation
diff --git a/pingsender/timer-pingsender/src/test/java/com/gojek/timer/pingsender/TimerPingSenderTest.kt b/pingsender/timer-pingsender/src/test/java/com/gojek/timer/pingsender/TimerPingSenderTest.kt
index 1e5e7313..e297698b 100644
--- a/pingsender/timer-pingsender/src/test/java/com/gojek/timer/pingsender/TimerPingSenderTest.kt
+++ b/pingsender/timer-pingsender/src/test/java/com/gojek/timer/pingsender/TimerPingSenderTest.kt
@@ -8,14 +8,14 @@ import com.nhaarman.mockitokotlin2.argumentCaptor
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
-import java.util.Timer
-import java.util.concurrent.TimeUnit
-import kotlin.test.assertEquals
import `in`.mohalla.paho.client.mqttv3.ILogger
import `in`.mohalla.paho.client.mqttv3.IMqttActionListener
import `in`.mohalla.paho.client.mqttv3.IMqttAsyncClient
import `in`.mohalla.paho.client.mqttv3.MqttToken
-import `in`.mohalla.phao.client.mqttv3.internal.ClientComms
+import `in`.mohalla.paho.client.mqttv3.internal.ClientComms
+import java.util.Timer
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/pingsender/workmanager-2.6.0-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderAdaptiveTest.kt b/pingsender/workmanager-2.6.0-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderAdaptiveTest.kt
index 5d3cd384..b2bc0ea1 100644
--- a/pingsender/workmanager-2.6.0-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderAdaptiveTest.kt
+++ b/pingsender/workmanager-2.6.0-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderAdaptiveTest.kt
@@ -9,14 +9,14 @@ import com.nhaarman.mockitokotlin2.argumentCaptor
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
-import java.util.concurrent.TimeUnit
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
import `in`.mohalla.paho.client.mqttv3.ILogger
import `in`.mohalla.paho.client.mqttv3.IMqttActionListener
import `in`.mohalla.paho.client.mqttv3.IMqttAsyncClient
import `in`.mohalla.paho.client.mqttv3.MqttToken
-import `in`.mohalla.phao.client.mqttv3.internal.ClientComms
+import `in`.mohalla.paho.client.mqttv3.internal.ClientComms
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/pingsender/workmanager-2.6.0-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderTest.kt b/pingsender/workmanager-2.6.0-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderTest.kt
index a14f462e..f6b24bae 100644
--- a/pingsender/workmanager-2.6.0-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderTest.kt
+++ b/pingsender/workmanager-2.6.0-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderTest.kt
@@ -6,14 +6,14 @@ import com.nhaarman.mockitokotlin2.argumentCaptor
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
-import java.util.concurrent.TimeUnit
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
import `in`.mohalla.paho.client.mqttv3.ILogger
import `in`.mohalla.paho.client.mqttv3.IMqttActionListener
import `in`.mohalla.paho.client.mqttv3.IMqttAsyncClient
import `in`.mohalla.paho.client.mqttv3.MqttToken
-import `in`.mohalla.phao.client.mqttv3.internal.ClientComms
+import `in`.mohalla.paho.client.mqttv3.internal.ClientComms
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/pingsender/workmanager-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderAdaptiveTest.kt b/pingsender/workmanager-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderAdaptiveTest.kt
index 5d3cd384..b2bc0ea1 100644
--- a/pingsender/workmanager-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderAdaptiveTest.kt
+++ b/pingsender/workmanager-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderAdaptiveTest.kt
@@ -9,14 +9,14 @@ import com.nhaarman.mockitokotlin2.argumentCaptor
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
-import java.util.concurrent.TimeUnit
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
import `in`.mohalla.paho.client.mqttv3.ILogger
import `in`.mohalla.paho.client.mqttv3.IMqttActionListener
import `in`.mohalla.paho.client.mqttv3.IMqttAsyncClient
import `in`.mohalla.paho.client.mqttv3.MqttToken
-import `in`.mohalla.phao.client.mqttv3.internal.ClientComms
+import `in`.mohalla.paho.client.mqttv3.internal.ClientComms
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
diff --git a/pingsender/workmanager-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderTest.kt b/pingsender/workmanager-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderTest.kt
index a14f462e..f6b24bae 100644
--- a/pingsender/workmanager-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderTest.kt
+++ b/pingsender/workmanager-pingsender/src/test/java/com/gojek/workmanager/pingsender/WorkManagerPingSenderTest.kt
@@ -6,14 +6,14 @@ import com.nhaarman.mockitokotlin2.argumentCaptor
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.nhaarman.mockitokotlin2.whenever
-import java.util.concurrent.TimeUnit
-import kotlin.test.assertFalse
-import kotlin.test.assertTrue
import `in`.mohalla.paho.client.mqttv3.ILogger
import `in`.mohalla.paho.client.mqttv3.IMqttActionListener
import `in`.mohalla.paho.client.mqttv3.IMqttAsyncClient
import `in`.mohalla.paho.client.mqttv3.MqttToken
-import `in`.mohalla.phao.client.mqttv3.internal.ClientComms
+import `in`.mohalla.paho.client.mqttv3.internal.ClientComms
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
From ec7b45bf6f6c076ed09ab51dd5bd2b92d523a11b Mon Sep 17 00:00:00 2001
From: ChandoraAnkit
Date: Fri, 31 Mar 2023 11:39:47 +0530
Subject: [PATCH 19/25] Fix APIs contract issues
---
mqtt-client/api/mqtt-client.api | 152 ++++++++++--------
.../mqtt-pingsender/api/mqtt-pingsender.api | 2 +-
2 files changed, 85 insertions(+), 69 deletions(-)
diff --git a/mqtt-client/api/mqtt-client.api b/mqtt-client/api/mqtt-client.api
index acf9fa4c..b4972b29 100644
--- a/mqtt-client/api/mqtt-client.api
+++ b/mqtt-client/api/mqtt-client.api
@@ -418,13 +418,14 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttConnectionLostEvent : com/
}
public final class com/gojek/mqtt/event/MqttEvent$MqttDisconnectCompleteEvent : com/gojek/mqtt/event/MqttEvent {
- public fun ()V
- public fun (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectCompleteEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectCompleteEvent;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectCompleteEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectCompleteEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectCompleteEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectCompleteEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public fun hashCode ()I
public fun setConnectionInfo (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
@@ -432,13 +433,14 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttDisconnectCompleteEvent :
}
public final class com/gojek/mqtt/event/MqttEvent$MqttDisconnectEvent : com/gojek/mqtt/event/MqttEvent {
- public fun ()V
- public fun (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectEvent;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public fun hashCode ()I
public fun setConnectionInfo (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
@@ -446,13 +448,14 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttDisconnectEvent : com/goje
}
public final class com/gojek/mqtt/event/MqttEvent$MqttDisconnectStartEvent : com/gojek/mqtt/event/MqttEvent {
- public fun ()V
- public fun (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectStartEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectStartEvent;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectStartEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectStartEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectStartEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttDisconnectStartEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public fun hashCode ()I
public fun setConnectionInfo (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
@@ -673,13 +676,14 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttPingSuccessEvent : com/goj
}
public final class com/gojek/mqtt/event/MqttEvent$MqttReconnectEvent : com/gojek/mqtt/event/MqttEvent {
- public fun ()V
- public fun (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttReconnectEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttReconnectEvent;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttReconnectEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttReconnectEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttReconnectEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttReconnectEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public fun hashCode ()I
public fun setConnectionInfo (Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
@@ -687,13 +691,15 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttReconnectEvent : com/gojek
}
public final class com/gojek/mqtt/event/MqttEvent$MqttSubscribeAttemptEvent : com/gojek/mqtt/event/MqttEvent {
- public fun (Ljava/util/Map;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Ljava/util/Map;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Ljava/util/Map;
- public final fun component2 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Ljava/util/Map;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeAttemptEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeAttemptEvent;Ljava/util/Map;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeAttemptEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Ljava/util/Map;
+ public final fun component3 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeAttemptEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeAttemptEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeAttemptEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public final fun getTopics ()Ljava/util/Map;
public fun hashCode ()I
@@ -702,15 +708,17 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttSubscribeAttemptEvent : co
}
public final class com/gojek/mqtt/event/MqttEvent$MqttSubscribeFailureEvent : com/gojek/mqtt/event/MqttEvent {
- public fun (Ljava/util/Map;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Ljava/util/Map;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Ljava/util/Map;
- public final fun component2 ()Lcom/gojek/mqtt/exception/CourierException;
- public final fun component3 ()J
- public final fun component4 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Ljava/util/Map;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeFailureEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeFailureEvent;Ljava/util/Map;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeFailureEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Ljava/util/Map;
+ public final fun component3 ()Lcom/gojek/mqtt/exception/CourierException;
+ public final fun component4 ()J
+ public final fun component5 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeFailureEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeFailureEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeFailureEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public final fun getException ()Lcom/gojek/mqtt/exception/CourierException;
public final fun getTimeTakenMillis ()J
@@ -721,14 +729,16 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttSubscribeFailureEvent : co
}
public final class com/gojek/mqtt/event/MqttEvent$MqttSubscribeSuccessEvent : com/gojek/mqtt/event/MqttEvent {
- public fun (Ljava/util/Map;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Ljava/util/Map;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Ljava/util/Map;
- public final fun component2 ()J
- public final fun component3 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Ljava/util/Map;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeSuccessEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeSuccessEvent;Ljava/util/Map;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeSuccessEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Ljava/util/Map;
+ public final fun component3 ()J
+ public final fun component4 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeSuccessEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeSuccessEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Map;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttSubscribeSuccessEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public final fun getTimeTakenMillis ()J
public final fun getTopics ()Ljava/util/Map;
@@ -738,13 +748,15 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttSubscribeSuccessEvent : co
}
public final class com/gojek/mqtt/event/MqttEvent$MqttUnsubscribeAttemptEvent : com/gojek/mqtt/event/MqttEvent {
- public fun (Ljava/util/Set;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Ljava/util/Set;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Ljava/util/Set;
- public final fun component2 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Ljava/util/Set;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeAttemptEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeAttemptEvent;Ljava/util/Set;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeAttemptEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Ljava/util/Set;
+ public final fun component3 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeAttemptEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeAttemptEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeAttemptEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public final fun getTopics ()Ljava/util/Set;
public fun hashCode ()I
@@ -753,15 +765,17 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttUnsubscribeAttemptEvent :
}
public final class com/gojek/mqtt/event/MqttEvent$MqttUnsubscribeFailureEvent : com/gojek/mqtt/event/MqttEvent {
- public fun (Ljava/util/Set;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Ljava/util/Set;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Ljava/util/Set;
- public final fun component2 ()Lcom/gojek/mqtt/exception/CourierException;
- public final fun component3 ()J
- public final fun component4 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Ljava/util/Set;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeFailureEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeFailureEvent;Ljava/util/Set;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeFailureEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Ljava/util/Set;
+ public final fun component3 ()Lcom/gojek/mqtt/exception/CourierException;
+ public final fun component4 ()J
+ public final fun component5 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeFailureEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeFailureEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;Lcom/gojek/mqtt/exception/CourierException;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeFailureEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public final fun getException ()Lcom/gojek/mqtt/exception/CourierException;
public final fun getTimeTakenMillis ()J
@@ -772,14 +786,16 @@ public final class com/gojek/mqtt/event/MqttEvent$MqttUnsubscribeFailureEvent :
}
public final class com/gojek/mqtt/event/MqttEvent$MqttUnsubscribeSuccessEvent : com/gojek/mqtt/event/MqttEvent {
- public fun (Ljava/util/Set;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
- public synthetic fun (Ljava/util/Set;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
- public final fun component1 ()Ljava/util/Set;
- public final fun component2 ()J
- public final fun component3 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
- public final fun copy (Ljava/util/Set;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeSuccessEvent;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeSuccessEvent;Ljava/util/Set;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeSuccessEvent;
+ public fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)V
+ public synthetic fun (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public final fun component1 ()Lcom/gojek/mqtt/network/ActiveNetInfo;
+ public final fun component2 ()Ljava/util/Set;
+ public final fun component3 ()J
+ public final fun component4 ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
+ public final fun copy (Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeSuccessEvent;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeSuccessEvent;Lcom/gojek/mqtt/network/ActiveNetInfo;Ljava/util/Set;JLcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;ILjava/lang/Object;)Lcom/gojek/mqtt/event/MqttEvent$MqttUnsubscribeSuccessEvent;
public fun equals (Ljava/lang/Object;)Z
+ public final fun getActiveNetInfo ()Lcom/gojek/mqtt/network/ActiveNetInfo;
public fun getConnectionInfo ()Lcom/gojek/mqtt/client/connectioninfo/ConnectionInfo;
public final fun getTimeTakenMillis ()J
public final fun getTopics ()Ljava/util/Set;
@@ -1030,7 +1046,7 @@ public final class com/gojek/mqtt/model/MqttConnectOptions {
public static final field Companion Lcom/gojek/mqtt/model/MqttConnectOptions$Companion;
public synthetic fun (Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun getClientId ()Ljava/lang/String;
- public final fun getConnectionSpec ()Lorg/eclipse/paho/client/mqttv3/ConnectionSpec;
+ public final fun getConnectionSpec ()Lin/mohalla/paho/client/mqttv3/ConnectionSpec;
public final fun getKeepAlive ()Lcom/gojek/mqtt/model/KeepAlive;
public final fun getPassword ()Ljava/lang/String;
public final fun getProtocols ()Ljava/util/List;
@@ -1052,7 +1068,7 @@ public final class com/gojek/mqtt/model/MqttConnectOptions$Builder {
public final fun build ()Lcom/gojek/mqtt/model/MqttConnectOptions;
public final fun cleanSession (Z)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
public final fun clientId (Ljava/lang/String;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
- public final fun connectionSpec (Lorg/eclipse/paho/client/mqttv3/ConnectionSpec;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
+ public final fun connectionSpec (Lin/mohalla/paho/client/mqttv3/ConnectionSpec;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
public final fun keepAlive (Lcom/gojek/mqtt/model/KeepAlive;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
public final fun mqttVersion (Lcom/gojek/mqtt/model/MqttVersion;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
public final fun password (Ljava/lang/String;)Lcom/gojek/mqtt/model/MqttConnectOptions$Builder;
diff --git a/pingsender/mqtt-pingsender/api/mqtt-pingsender.api b/pingsender/mqtt-pingsender/api/mqtt-pingsender.api
index 7debc9dc..ded64793 100644
--- a/pingsender/mqtt-pingsender/api/mqtt-pingsender.api
+++ b/pingsender/mqtt-pingsender/api/mqtt-pingsender.api
@@ -5,7 +5,7 @@ public final class com/gojek/mqtt/pingsender/KeepAliveKt {
}
public abstract interface class com/gojek/mqtt/pingsender/MqttPingSender {
- public abstract fun init (Lorg/eclipse/paho/client/mqttv3/internal/ClientComms;Lorg/eclipse/paho/client/mqttv3/ILogger;)V
+ public abstract fun init (Lin/mohalla/paho/client/mqttv3/internal/ClientComms;Lin/mohalla/paho/client/mqttv3/ILogger;)V
public abstract fun schedule (J)V
public abstract fun start ()V
public abstract fun stop ()V
From 692bb33f00bb16b63710806dad20cf7214230471 Mon Sep 17 00:00:00 2001
From: ChandoraAnkit
Date: Fri, 31 Mar 2023 14:47:25 +0530
Subject: [PATCH 20/25] Update gitVersionName to 0.2.0
---
gradle/script-ext.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gradle/script-ext.gradle b/gradle/script-ext.gradle
index fb332678..76cbe66f 100644
--- a/gradle/script-ext.gradle
+++ b/gradle/script-ext.gradle
@@ -1,5 +1,5 @@
ext {
gitVersionCode = ""//grgit.tag.list().size()
- gitVersionName = "0.1.0"//grgit.describe(tags: true, always: true)
+ gitVersionName = "0.2.0"//grgit.describe(tags: true, always: true)
println("version : $gitVersionName")
}
From 89b433dbcbc70f850231beb17605d9e6061dadce Mon Sep 17 00:00:00 2001
From: Anubhav Gupta
Date: Tue, 11 Apr 2023 14:51:22 +0530
Subject: [PATCH 21/25] add new functionality for qos1 without persistence
(#62)
* add new functionality for qos1 without persistence
* fixed review comments and handled case for removal of msgids for qos1 without persistence messages
* fixed review comment
* updated docs
* change from entry to subscription flag model
* removed unused import
* review comments
* fixed spotless
---
.../mapper/MqttTransactionUiModelMapper.kt | 2 +-
courier-core/api/courier-core.api | 3 ++
.../src/main/java/com/gojek/courier/QoS.kt | 22 +++++++++--
docs/docs/QoS.md | 15 +++++++-
.../gojek/mqtt/client/model/MqttSendPacket.kt | 7 +++-
.../mqtt/client/v3/impl/AndroidMqttClient.kt | 5 ++-
.../gojek/mqtt/connection/IMqttConnection.kt | 2 +-
.../gojek/mqtt/connection/MqttConnection.kt | 37 +++++++++++++++----
.../paho/client/mqttv3/IMqttAsyncClient.java | 8 ++++
.../paho/client/mqttv3/MqttAsyncClient.java | 32 ++++++++++++++--
.../paho/client/mqttv3/MqttMessage.java | 12 ++++++
.../client/mqttv3/internal/ClientState.java | 35 +++++++++++++-----
.../client/mqttv3/internal/CommsSender.java | 10 ++++-
.../mqttv3/internal/wire/MqttPublish.java | 7 ++--
.../mqttv3/internal/wire/MqttSubscribe.java | 26 +++++++++++--
.../mqttv3/internal/wire/SubscribeFlags.java | 21 +++++++++++
16 files changed, 205 insertions(+), 39 deletions(-)
create mode 100644 paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/SubscribeFlags.java
diff --git a/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt b/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt
index c23ed6f9..eefe30de 100644
--- a/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt
+++ b/chuck-mqtt/src/main/java/com/gojek/chuckmqtt/internal/presentation/mapper/MqttTransactionUiModelMapper.kt
@@ -202,7 +202,7 @@ internal class MqttTransactionUiModelMapper : Mapper {
sb.append("PUBLISH \n")
sb.append("Qos : ${mqttWireMessage.message.qos} \n")
- if (mqttWireMessage.message.qos > 0) {
+ if (mqttWireMessage.message.qos > 0 || mqttWireMessage.message.type > 2) {
sb.append("MsgId : ${mqttWireMessage.messageId} \n")
}
sb.append("Retained : ${mqttWireMessage.message.isRetained} \n")
diff --git a/courier-core/api/courier-core.api b/courier-core/api/courier-core.api
index e4ca55c0..edccd6e2 100644
--- a/courier-core/api/courier-core.api
+++ b/courier-core/api/courier-core.api
@@ -19,8 +19,11 @@ public abstract interface class com/gojek/courier/MessageAdapter$Factory {
public final class com/gojek/courier/QoS : java/lang/Enum {
public static final field ONE Lcom/gojek/courier/QoS;
+ public static final field ONE_WITHOUT_PERSISTENCE_AND_NO_RETRY Lcom/gojek/courier/QoS;
+ public static final field ONE_WITHOUT_PERSISTENCE_AND_RETRY Lcom/gojek/courier/QoS;
public static final field TWO Lcom/gojek/courier/QoS;
public static final field ZERO Lcom/gojek/courier/QoS;
+ public final fun getType ()I
public final fun getValue ()I
public static fun valueOf (Ljava/lang/String;)Lcom/gojek/courier/QoS;
public static fun values ()[Lcom/gojek/courier/QoS;
diff --git a/courier-core/src/main/java/com/gojek/courier/QoS.kt b/courier-core/src/main/java/com/gojek/courier/QoS.kt
index 5fcf5167..5bda5549 100644
--- a/courier-core/src/main/java/com/gojek/courier/QoS.kt
+++ b/courier-core/src/main/java/com/gojek/courier/QoS.kt
@@ -1,7 +1,21 @@
package com.gojek.courier
-enum class QoS(val value: Int) {
- ZERO(0),
- ONE(1),
- TWO(2)
+enum class QoS(val value: Int, val type: Int) {
+ // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718100
+ ZERO(0, 0),
+
+ // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718100
+ ONE(1, 1),
+
+ // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718100
+ TWO(2, 2),
+
+ /** Like QoS1, Message delivery is acknowledged with PUBACK, but unlike QoS1 messages are
+ neither persisted nor retried at send after one attempt.
+ The message arrives at the receiver either once or not at all **/
+ ONE_WITHOUT_PERSISTENCE_AND_NO_RETRY(0, 3),
+
+ /** Like QoS1, Message delivery is acknowledged with PUBACK, but unlike QoS1 messages are
+ not persisted. The messages are retried within active connection if delivery is not acknowledged.**/
+ ONE_WITHOUT_PERSISTENCE_AND_RETRY(0, 4)
}
diff --git a/docs/docs/QoS.md b/docs/docs/QoS.md
index f9f78784..60aacb7b 100644
--- a/docs/docs/QoS.md
+++ b/docs/docs/QoS.md
@@ -11,4 +11,17 @@ When you talk about QoS in MQTT, you need to consider the two sides of message d
- Message delivery form the publishing client to the broker.
- Message delivery from the broker to the subscribing client.
-You can read more about the detail of QoS in MQTT from [HiveMQ site](https://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels/).
\ No newline at end of file
+You can read more about the detail of QoS in MQTT from [HiveMQ site](https://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels/).
+
+:warning: **
+These are non standard QoS options. You need to have compatible broker to use these QoS options
+
+We added two more Qos options
+
+- QoS1 with no persistence and no retry: Like QoS1, Message delivery is acknowledged with PUBACK, but unlike QoS1 messages are
+ neither persisted nor retried at send after one attempt. The message arrives at the receiver either once or not at all
+- QoS1 with no persistence and with retry: Like QoS1, Message delivery is acknowledged with PUBACK, but unlike QoS1 messages are
+ not persisted. The messages are retried within active connection if delivery is not acknowledged.
+
+ Note: Both these Qos options have same behaviour (without retry) during publish and
+different behaviour for subscribe
\ No newline at end of file
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/model/MqttSendPacket.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/model/MqttSendPacket.kt
index 3382b130..50c96220 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/model/MqttSendPacket.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/model/MqttSendPacket.kt
@@ -8,14 +8,16 @@ internal data class MqttSendPacket(
var messageId: Long,
var timestamp: Long,
var qos: Int,
- var topic: String
+ var topic: String,
+ var type: Int
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.createByteArray()!!,
parcel.readLong(),
parcel.readLong(),
parcel.readInt(),
- parcel.readString()!!
+ parcel.readString()!!,
+ parcel.readInt()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
@@ -24,6 +26,7 @@ internal data class MqttSendPacket(
parcel.writeLong(timestamp)
parcel.writeInt(qos)
parcel.writeString(topic)
+ parcel.writeInt(type)
}
override fun describeContents(): Int {
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
index 65209a5f..92f498b4 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
@@ -251,7 +251,7 @@ internal class AndroidMqttClient(
MqttMessageSendEvent(topic, qos, message.size)
)
}
- mqttConnection.publish(mqttPacket, mqttPacket.qos, mqttPacket.topic)
+ mqttConnection.publish(mqttPacket)
} catch (e: MqttPersistenceException) {
with(mqttPacket) {
eventHandler.onEvent(
@@ -297,7 +297,8 @@ internal class AndroidMqttClient(
0,
System.currentTimeMillis(),
mqttPacket.qos.value,
- mqttPacket.topic
+ mqttPacket.topic,
+ mqttPacket.qos.type
)
val msg = Message.obtain()
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/connection/IMqttConnection.kt b/mqtt-client/src/main/java/com/gojek/mqtt/connection/IMqttConnection.kt
index 6cd20814..790f3baf 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/connection/IMqttConnection.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/connection/IMqttConnection.kt
@@ -17,7 +17,7 @@ internal interface IMqttConnection {
fun subscribe(topicMap: Map)
fun unsubscribe(topics: Set)
- fun publish(mqttPacket: MqttSendPacket, qos: Int, topic: String)
+ fun publish(mqttPacket: MqttSendPacket)
fun disconnect()
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/connection/MqttConnection.kt b/mqtt-client/src/main/java/com/gojek/mqtt/connection/MqttConnection.kt
index 804bb047..97761d6c 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/connection/MqttConnection.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/connection/MqttConnection.kt
@@ -3,6 +3,8 @@ package com.gojek.mqtt.connection
import android.content.Context
import android.os.SystemClock
import com.gojek.courier.QoS
+import com.gojek.courier.QoS.ONE_WITHOUT_PERSISTENCE_AND_NO_RETRY
+import com.gojek.courier.QoS.ONE_WITHOUT_PERSISTENCE_AND_RETRY
import com.gojek.courier.extensions.fromNanosToMillis
import com.gojek.courier.logging.ILogger
import com.gojek.courier.utils.Clock
@@ -44,6 +46,7 @@ import org.eclipse.paho.client.mqttv3.MqttException.REASON_CODE_UNEXPECTED_ERROR
import org.eclipse.paho.client.mqttv3.MqttMessage
import org.eclipse.paho.client.mqttv3.MqttSecurityException
import org.eclipse.paho.client.mqttv3.internal.wire.MqttSuback
+import org.eclipse.paho.client.mqttv3.internal.wire.SubscribeFlags
import org.eclipse.paho.client.mqttv3.internal.wire.UserProperty
internal class MqttConnection(
@@ -224,16 +227,15 @@ internal class MqttConnection(
}
override fun publish(
- mqttPacket: MqttSendPacket,
- qos: Int,
- topic: String
+ mqttPacket: MqttSendPacket
) {
logger.d(TAG, "Current inflight msg count : " + mqtt!!.inflightMessages)
- mqtt!!.publish(
- topic,
+ mqtt!!.publishWithNewType(
+ mqttPacket.topic,
mqttPacket.message,
- qos,
+ mqttPacket.qos,
+ mqttPacket.type,
false,
mqttPacket,
object : IMqttActionListenerNew {
@@ -465,16 +467,35 @@ internal class MqttConnection(
if (topicMap.isNotEmpty()) {
val topicArray: Array = topicMap.keys.toTypedArray()
val qosArray = IntArray(topicMap.size)
+ val subscribeFlagList = ArrayList(topicMap.size)
for ((index, qos) in topicMap.values.withIndex()) {
- qosArray[index] = qos.value
+ if (qos == ONE_WITHOUT_PERSISTENCE_AND_NO_RETRY || qos == ONE_WITHOUT_PERSISTENCE_AND_RETRY) {
+ qosArray[index] = 1
+ } else {
+ qosArray[index] = qos.value
+ }
+ }
+ for ((index, qos) in topicMap.values.withIndex()) {
+ when (qos) {
+ ONE_WITHOUT_PERSISTENCE_AND_NO_RETRY -> {
+ subscribeFlagList.add(index, SubscribeFlags(false, false))
+ }
+ ONE_WITHOUT_PERSISTENCE_AND_RETRY -> {
+ subscribeFlagList.add(index, SubscribeFlags(false, true))
+ }
+ else -> {
+ subscribeFlagList.add(index, SubscribeFlags(true, true))
+ }
+ }
}
val subscribeStartTime = clock.nanoTime()
try {
logger.d(TAG, "Subscribing to topics: ${topicMap.keys}")
connectionConfig.connectionEventHandler.onMqttSubscribeAttempt(topicMap)
- mqtt!!.subscribe(
+ mqtt!!.subscribeWithPersistableRetryableFlags(
topicArray,
qosArray,
+ subscribeFlagList,
MqttContext(subscribeStartTime),
getSubscribeListener(topicMap)
)
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/IMqttAsyncClient.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/IMqttAsyncClient.java
index 79cf4e0f..698ea5fb 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/IMqttAsyncClient.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/IMqttAsyncClient.java
@@ -1,5 +1,10 @@
package org.eclipse.paho.client.mqttv3;
+import org.eclipse.paho.client.mqttv3.internal.wire.SubscribeFlags;
+
+import java.util.List;
+import java.util.Map;
+
/**
* Enables an application to communicate with an MQTT server using non-blocking methods.
*
@@ -616,6 +621,9 @@ public IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean
*/
public IMqttToken subscribe(String[] topicFilters, int[] qos, Object userContext, IMqttActionListener callback) throws MqttException;
+ public IMqttToken subscribeWithPersistableRetryableFlags(String[] topicFilters, int[] qos,
+ List subscribeFlagsList, Object userContext, IMqttActionListener callback) throws MqttException;
+
/**
* Requests the server unsubscribe the client from a topic.
*
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttAsyncClient.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttAsyncClient.java
index 45a8bf38..03cade6a 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttAsyncClient.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttAsyncClient.java
@@ -34,13 +34,18 @@
import org.eclipse.paho.client.mqttv3.internal.wire.MqttPublish;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttSubscribe;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttUnsubscribe;
+import org.eclipse.paho.client.mqttv3.internal.wire.SubscribeFlags;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
+import java.util.AbstractMap;
+import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
@@ -913,8 +918,22 @@ public IMqttToken subscribe(String[] topicFilters, int[] qos) throws MqttExcepti
*
* @see org.eclipse.paho.client.mqttv3.IMqttAsyncClient#subscribe(java.lang.String[], int[], java.lang.Object, org.eclipse.paho.client.mqttv3.IMqttActionListener)
*/
- public IMqttToken subscribe(String[] topicFilters, int[] qos, Object userContext, IMqttActionListener callback) throws MqttException
- {
+
+ public IMqttToken subscribe(String[] topicFilters, int[] qos, Object userContext, IMqttActionListener callback) throws MqttException {
+ List subscribeFlagsList = new ArrayList<>();
+ for(int i = 0; i < qos.length ; i++) {
+ subscribeFlagsList.add(new SubscribeFlags(true, true));
+ }
+ return subscribeWithPersistableRetryableFlags(topicFilters, qos, subscribeFlagsList, userContext, callback);
+ }
+
+ public IMqttToken subscribeWithPersistableRetryableFlags(
+ String[] topicFilters,
+ int[] qos,
+ List subscribeFlagsList,
+ Object userContext,
+ IMqttActionListener callback
+ ) throws MqttException {
final String methodName = "subscribe";
if (topicFilters.length != qos.length)
@@ -942,7 +961,7 @@ public IMqttToken subscribe(String[] topicFilters, int[] qos, Object userContext
token.setUserContext(userContext);
token.internalTok.setTopics(topicFilters);
- MqttSubscribe register = new MqttSubscribe(topicFilters, qos);
+ MqttSubscribe register = new MqttSubscribe(topicFilters, qos, subscribeFlagsList);
comms.sendNoWait(register, token);
// @TRACE 109=<
@@ -1062,9 +1081,16 @@ public IMqttDeliveryToken[] getPendingDeliveryTokens()
*/
public IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean retained, Object userContext, IMqttActionListener callback) throws MqttException,
MqttPersistenceException
+ {
+ return this.publishWithNewType(topic, payload, qos, qos, retained, userContext, callback);
+ }
+
+ public IMqttDeliveryToken publishWithNewType(String topic, byte[] payload, int qos, int type, boolean retained, Object userContext, IMqttActionListener callback) throws MqttException,
+ MqttPersistenceException
{
MqttMessage message = new MqttMessage(payload);
message.setQos(qos);
+ message.setType(type);
message.setRetained(retained);
return this.publish(topic, message, userContext, callback);
}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttMessage.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttMessage.java
index a6c6f4bd..d70bd889 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttMessage.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/MqttMessage.java
@@ -28,6 +28,8 @@ public class MqttMessage
private int qos = 1;
+ private int type = -1;
+
private boolean retained = false;
private boolean dup = false;
@@ -148,6 +150,10 @@ public int getQos()
return qos;
}
+ public int getType()
+ {
+ return type;
+ }
/**
* Sets the quality of service for this message.
*
@@ -180,6 +186,12 @@ public void setQos(int qos)
this.qos = qos;
}
+ public void setType(int type)
+ {
+ checkMutable();
+ this.type = type;
+ }
+
/**
* Returns a string representation of this message's payload. Makes an attempt to return the payload as a string. As the MQTT client has no control over the content of the
* payload it may fail.
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/ClientState.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/ClientState.java
index 2e50f942..c38cc94a 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/ClientState.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/ClientState.java
@@ -15,7 +15,6 @@
*/
package org.eclipse.paho.client.mqttv3.internal;
-
import org.eclipse.paho.client.mqttv3.ICommsCallback;
import org.eclipse.paho.client.mqttv3.IExperimentsConfig;
import org.eclipse.paho.client.mqttv3.ILogger;
@@ -46,6 +45,7 @@
import java.io.EOFException;
import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.Map;
import java.util.Properties;
import java.util.Vector;
@@ -93,6 +93,8 @@ public class ClientState
private Hashtable inUseMsgIds; // Used to store a set of in-use message IDs
+ private Hashtable inUseMsdIdsQos1WithoutPersistence;
+
volatile private Vector pendingMessages;
volatile private Vector pendingFlows;
@@ -169,6 +171,7 @@ protected ClientState(
this.maxInflight = maxInflightMsgs;
inUseMsgIds = new Hashtable();
+ inUseMsdIdsQos1WithoutPersistence = new Hashtable();
pendingMessages = new Vector(this.maxInflight);
pendingFlows = new Vector();
outboundQoS2 = new Hashtable();
@@ -234,6 +237,7 @@ protected void clearState() throws MqttException
persistence.clear();
clientComms.clear();
inUseMsgIds.clear();
+ inUseMsdIdsQos1WithoutPersistence.clear();
pendingMessages.clear();
pendingFlows.clear();
outboundQoS2.clear();
@@ -516,7 +520,8 @@ public void send(MqttWireMessage message, MqttToken token) throws MqttException
final String methodName = "send";
if (message.isMessageIdRequired() && (message.getMessageId() == 0))
{
- message.setMessageId(getNextMessageId());
+ boolean isQos1NonPersistenceMessage = (message instanceof MqttPublish) && (((MqttPublish) message).getMessage().getType() > 2);
+ message.setMessageId(getNextMessageId(isQos1NonPersistenceMessage));
}
if (token != null)
{
@@ -555,6 +560,7 @@ public void send(MqttWireMessage message, MqttToken token) throws MqttException
persistence.put(getSendPersistenceKey(message), (MqttPublish) message);
break;
}
+
tokenStore.saveToken(token, message);
pendingMessages.addElement(message);
queueLock.notifyAll();
@@ -939,7 +945,7 @@ protected void notifySent(MqttWireMessage message)
token.internalTok.notifySent();
if (message instanceof MqttPublish)
{
- if (((MqttPublish) message).getMessage().getQos() == 0)
+ if (((MqttPublish) message).getMessage().getQos() == 0 && ((MqttPublish) message).getMessage().getType() == 0)
{
// once a QoS 0 message is sent we can clean up its records straight away as
// we won't be hearing about it again
@@ -1021,7 +1027,7 @@ protected boolean checkQuiesceLock()
/**
* Called by the CommsReceiver when an ack has arrived.
*
- * @param message
+ * @param ack
* @throws MqttException
*/
protected void notifyReceivedAck(MqttAck ack) throws MqttException
@@ -1169,7 +1175,7 @@ else if (message instanceof MqttPubRel)
* Called when waiters and callbacks have processed the message. For messages where delivery is complete the message can be removed from persistence and counters adjusted
* accordingly. Also tidy up by removing token from store...
*
- * @param message
+ * @param token
* @throws MqttException
*/
protected void notifyComplete(MqttToken token) throws MqttException
@@ -1323,11 +1329,15 @@ public void disconnected(MqttException reason)
try
{
- if (cleanSession)
- {
+ if (cleanSession) {
clearState();
}
+ for (Integer key : inUseMsdIdsQos1WithoutPersistence.keySet()) {
+ inUseMsgIds.remove(key);
+ }
+ inUseMsdIdsQos1WithoutPersistence.clear();
+
pendingMessages.clear();
pendingFlows.clear();
synchronized (pingOutstanding)
@@ -1348,17 +1358,19 @@ public void disconnected(MqttException reason)
* @param msgId
* A message ID that can be freed up for re-use.
*/
- private synchronized void releaseMessageId(int msgId)
+ public synchronized void releaseMessageId(int msgId)
{
inUseMsgIds.remove(Integer.valueOf(msgId));
+ inUseMsdIdsQos1WithoutPersistence.remove(Integer.valueOf(msgId));
}
/**
* Get the next MQTT message ID that is not already in use, and marks it as now being in use.
*
* @return the next MQTT message ID to use
+ * @param isQos1NonPersistenceMessage
*/
- private synchronized int getNextMessageId() throws MqttException
+ private synchronized int getNextMessageId(boolean isQos1NonPersistenceMessage) throws MqttException
{
int startingMessageId = nextMsgId;
// Allow two complete passes of the message ID range. This gives
@@ -1383,6 +1395,7 @@ private synchronized int getNextMessageId() throws MqttException
while (inUseMsgIds.containsKey(Integer.valueOf(nextMsgId)));
Integer id = Integer.valueOf(nextMsgId);
inUseMsgIds.put(id, id);
+ if(isQos1NonPersistenceMessage) inUseMsdIdsQos1WithoutPersistence.put(id, id);
return nextMsgId;
}
@@ -1469,6 +1482,7 @@ protected void deliveryComplete(MqttPublish message) throws MqttPersistenceExcep
protected void close()
{
inUseMsgIds.clear();
+ inUseMsdIdsQos1WithoutPersistence.clear();
pendingMessages.clear();
pendingFlows.clear();
outboundQoS2.clear();
@@ -1476,6 +1490,7 @@ protected void close()
inboundQoS2.clear();
tokenStore.clear();
inUseMsgIds = null;
+ inUseMsdIdsQos1WithoutPersistence = null;
pendingMessages = null;
pendingFlows = null;
outboundQoS2 = null;
@@ -1552,7 +1567,7 @@ public void persistBufferedMessage(MqttWireMessage message) throws MqttException
// Because the client will have disconnected, we will want to re-open persistence
try {
- message.setMessageId(getNextMessageId());
+ message.setMessageId(getNextMessageId(false));
key = getSendBufferedPersistenceKey(message);
try {
persistence.put(key, (MqttPublish) message);
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/CommsSender.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/CommsSender.java
index 0c11f6f5..3d765483 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/CommsSender.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/CommsSender.java
@@ -281,8 +281,16 @@ private void handleRunException(MqttWireMessage message, Exception ex)
{
mex = (MqttException) ex;
}
-
+ if((message instanceof MqttPublish) && (
+ (((MqttPublish) message)).getMessage().getQos() == 0
+ || (((MqttPublish) message)).getMessage().getType() > 2
+ )
+ ) {
+ clientState.releaseMessageId(message.getMessageId());
+ }
+ clientState.releaseMessageId(message.getType());
running = false;
+
clientComms.shutdownConnection(null, mex);
}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/MqttPublish.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/MqttPublish.java
index 26de5774..c2ef225d 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/MqttPublish.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/MqttPublish.java
@@ -114,7 +114,7 @@ public String toString()
StringBuffer sb = new StringBuffer();
sb.append(super.toString());
sb.append(" qos:" + message.getQos());
- if (message.getQos() > 0)
+ if (message.getQos() > 0 || message.getType() > 2)
{
sb.append(" msgId:" + msgId);
}
@@ -130,7 +130,8 @@ public String toString()
protected byte getMessageInfo()
{
- byte info = (byte) (message.getQos() << 1);
+ int qos = message.getType() > 2 ? 1 : message.getQos();
+ byte info = (byte) (qos << 1);
if (message.isRetained())
{
info |= 0x01;
@@ -196,7 +197,7 @@ protected byte[] getVariableHeader() throws MqttException
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
encodeUTF8(dos, topicName);
- if (message.getQos() > 0)
+ if (message.getQos() > 0 || message.getType() > 2)
{
dos.writeShort(msgId);
}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/MqttSubscribe.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/MqttSubscribe.java
index 04a818cf..cf111809 100644
--- a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/MqttSubscribe.java
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/MqttSubscribe.java
@@ -20,6 +20,9 @@
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
@@ -33,6 +36,8 @@ public class MqttSubscribe extends MqttWireMessage
private int[] qos;
+ List subscribeFlagsList;
+
private int count;
/**
@@ -51,13 +56,19 @@ public MqttSubscribe(byte info, byte[] data) throws IOException
count = 0;
names = new String[10];
qos = new int[10];
+ subscribeFlagsList = new ArrayList<>(10);
boolean end = false;
while (!end)
{
try
{
names[count] = decodeUTF8(dis);
- qos[count++] = dis.readByte();
+
+ byte qosAndFlagByte = dis.readByte();
+ qos[count++] = qosAndFlagByte & 0x3;
+ boolean isPersistable = (qosAndFlagByte & 0x04) == 0;
+ boolean isRetryable = (qosAndFlagByte & 0x08) == 0;
+ subscribeFlagsList.add(new SubscribeFlags(isPersistable, isRetryable));
}
catch (Exception e)
{
@@ -75,11 +86,12 @@ public MqttSubscribe(byte info, byte[] data) throws IOException
* @param qos
* - the max QoS that each each topic will be subscribed at
*/
- public MqttSubscribe(String[] names, int[] qos)
+ public MqttSubscribe(String[] names, int[] qos, List subscribeFlagsList)
{
super(MqttWireMessage.MESSAGE_TYPE_SUBSCRIBE);
this.names = names;
this.qos = qos;
+ this.subscribeFlagsList = subscribeFlagsList;
this.count = names.length;
if (names.length != qos.length)
@@ -153,7 +165,15 @@ public byte[] getPayload() throws MqttException
for (int i = 0; i < names.length; i++)
{
encodeUTF8(dos, names[i]);
- dos.writeByte(qos[i]);
+ byte nextByte = 0;
+ nextByte = (byte) (nextByte | qos[i]);
+ if (!subscribeFlagsList.get(i).isPersistableFlagEnabled()) {
+ nextByte |= 0x04;
+ }
+ if (!subscribeFlagsList.get(i).isRetryableFlagEnabled()) {
+ nextByte |= 0x08;
+ }
+ dos.writeByte(nextByte);
}
return baos.toByteArray();
}
diff --git a/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/SubscribeFlags.java b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/SubscribeFlags.java
new file mode 100644
index 00000000..50406bc8
--- /dev/null
+++ b/paho/src/main/java/org/eclipse/paho/client/mqttv3/internal/wire/SubscribeFlags.java
@@ -0,0 +1,21 @@
+package org.eclipse.paho.client.mqttv3.internal.wire;
+
+public class SubscribeFlags {
+
+ private final boolean isPersistable;
+
+ private final boolean isRetryable;
+
+ public SubscribeFlags(boolean isPersistable, boolean isRetryable){
+ this.isPersistable = isPersistable;
+ this.isRetryable = isRetryable;
+ }
+
+ public boolean isPersistableFlagEnabled() {
+ return isPersistable;
+ }
+
+ public boolean isRetryableFlagEnabled() {
+ return isRetryable;
+ }
+}
From 8d10dafb0292e19e45489e991b2d211979731249 Mon Sep 17 00:00:00 2001
From: Deepanshu
Date: Wed, 12 Apr 2023 14:25:24 +0530
Subject: [PATCH 22/25] Add config for max inflight messages limit (#63)
---
.../main/java/com/gojek/courier/app/ui/MainActivity.kt | 1 +
mqtt-client/api/mqtt-client.api | 10 ++++++----
.../com/gojek/mqtt/client/config/ExperimentConfigs.kt | 4 +++-
.../com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt | 3 +--
4 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt b/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt
index 40c344a4..2244ce47 100644
--- a/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt
+++ b/app/src/main/java/com/gojek/courier/app/ui/MainActivity.kt
@@ -131,6 +131,7 @@ class MainActivity : AppCompatActivity() {
activityCheckIntervalSeconds = 30,
incomingMessagesTTLSecs = 60,
incomingMessagesCleanupIntervalSecs = 10,
+ maxInflightMessagesLimit = 1000,
),
pingSender = WorkPingSenderFactory.createMqttPingSender(applicationContext, WorkManagerPingSenderConfig())
)
diff --git a/mqtt-client/api/mqtt-client.api b/mqtt-client/api/mqtt-client.api
index acf9fa4c..ca006f6f 100644
--- a/mqtt-client/api/mqtt-client.api
+++ b/mqtt-client/api/mqtt-client.api
@@ -28,8 +28,8 @@ public abstract interface class com/gojek/mqtt/client/MqttInterceptor {
public final class com/gojek/mqtt/client/config/ExperimentConfigs {
public fun ()V
- public fun (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZ)V
- public synthetic fun (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZI)V
+ public synthetic fun (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZIILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Lcom/gojek/mqtt/client/config/SubscriptionStore;
public final fun component2 ()Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;
public final fun component3 ()I
@@ -38,14 +38,16 @@ public final class com/gojek/mqtt/client/config/ExperimentConfigs {
public final fun component6 ()J
public final fun component7 ()J
public final fun component8 ()Z
- public final fun copy (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZ)Lcom/gojek/mqtt/client/config/ExperimentConfigs;
- public static synthetic fun copy$default (Lcom/gojek/mqtt/client/config/ExperimentConfigs;Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZILjava/lang/Object;)Lcom/gojek/mqtt/client/config/ExperimentConfigs;
+ public final fun component9 ()I
+ public final fun copy (Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZI)Lcom/gojek/mqtt/client/config/ExperimentConfigs;
+ public static synthetic fun copy$default (Lcom/gojek/mqtt/client/config/ExperimentConfigs;Lcom/gojek/mqtt/client/config/SubscriptionStore;Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;IIIJJZIILjava/lang/Object;)Lcom/gojek/mqtt/client/config/ExperimentConfigs;
public fun equals (Ljava/lang/Object;)Z
public final fun getActivityCheckIntervalSeconds ()I
public final fun getAdaptiveKeepAliveConfig ()Lcom/gojek/mqtt/model/AdaptiveKeepAliveConfig;
public final fun getInactivityTimeoutSeconds ()I
public final fun getIncomingMessagesCleanupIntervalSecs ()J
public final fun getIncomingMessagesTTLSecs ()J
+ public final fun getMaxInflightMessagesLimit ()I
public final fun getPolicyResetTimeSeconds ()I
public final fun getShouldUseNewSSLFlow ()Z
public final fun getSubscriptionStore ()Lcom/gojek/mqtt/client/config/SubscriptionStore;
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/ExperimentConfigs.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/ExperimentConfigs.kt
index 2f1d863d..d0421ca0 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/config/ExperimentConfigs.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/config/ExperimentConfigs.kt
@@ -4,6 +4,7 @@ import com.gojek.mqtt.client.config.SubscriptionStore.PERSISTABLE
import com.gojek.mqtt.constants.DEFAULT_ACTIVITY_CHECK_INTERVAL_SECS
import com.gojek.mqtt.constants.DEFAULT_INACTIVITY_TIMEOUT_SECS
import com.gojek.mqtt.constants.DEFAULT_POLICY_RESET_TIME_SECS
+import com.gojek.mqtt.constants.MAX_INFLIGHT_MESSAGES_ALLOWED
import com.gojek.mqtt.model.AdaptiveKeepAliveConfig
data class ExperimentConfigs(
@@ -14,7 +15,8 @@ data class ExperimentConfigs(
val policyResetTimeSeconds: Int = DEFAULT_POLICY_RESET_TIME_SECS,
val incomingMessagesTTLSecs: Long = 360,
val incomingMessagesCleanupIntervalSecs: Long = 60,
- val shouldUseNewSSLFlow: Boolean = false
+ val shouldUseNewSSLFlow: Boolean = false,
+ val maxInflightMessagesLimit: Int = MAX_INFLIGHT_MESSAGES_ALLOWED
)
enum class SubscriptionStore {
diff --git a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
index 92f498b4..e69da2da 100644
--- a/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
+++ b/mqtt-client/src/main/java/com/gojek/mqtt/client/v3/impl/AndroidMqttClient.kt
@@ -40,7 +40,6 @@ import com.gojek.mqtt.client.v3.IAndroidMqttClient
import com.gojek.mqtt.connection.IMqttConnection
import com.gojek.mqtt.connection.MqttConnection
import com.gojek.mqtt.connection.config.v3.ConnectionConfig
-import com.gojek.mqtt.constants.MAX_INFLIGHT_MESSAGES_ALLOWED
import com.gojek.mqtt.constants.MESSAGE
import com.gojek.mqtt.constants.MSG_APP_PUBLISH
import com.gojek.mqtt.event.EventHandler
@@ -170,7 +169,7 @@ internal class AndroidMqttClient(
subscriptionRetryPolicy = mqttConfiguration.subscriptionRetryPolicy,
unsubscriptionRetryPolicy = mqttConfiguration.unsubscriptionRetryPolicy,
wakeLockTimeout = mqttConfiguration.wakeLockTimeout,
- maxInflightMessages = MAX_INFLIGHT_MESSAGES_ALLOWED,
+ maxInflightMessages = experimentConfigs.maxInflightMessagesLimit,
logger = mqttConfiguration.logger,
connectionEventHandler = mqttClientEventAdapter.adapt(),
mqttInterceptorList = mqttConfiguration.mqttInterceptorList.map {
From 9b08b653ea2e7077f642840b2dc5b24418fb5f49 Mon Sep 17 00:00:00 2001
From: deepanshu42
Date: Tue, 18 Apr 2023 10:47:07 +0530
Subject: [PATCH 23/25] Add debug logs in Coordinator
---
.../gojek/courier/coordinator/Coordinator.kt | 28 +++++++++++++++----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
index c93a085f..c221db2a 100644
--- a/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
+++ b/courier/src/main/java/com/gojek/courier/coordinator/Coordinator.kt
@@ -30,15 +30,20 @@ internal class Coordinator(
@Synchronized
override fun send(stubMethod: StubMethod.Send, args: Array): Any {
+ logger.d("Coordinator", "Send method invoked")
val data = stubMethod.argumentProcessor.getDataArgument(args)
stubMethod.argumentProcessor.inject(args)
val topic = stubMethod.argumentProcessor.getTopic()
val message = stubMethod.messageAdapter.toMessage(topic, data)
- return client.send(message, topic, stubMethod.qos)
+ val qos = stubMethod.qos
+ val sent = client.send(message, topic, qos)
+ logger.d("Coordinator", "Sending message on topic: $topic, qos: $qos, message: $data")
+ return sent
}
@Synchronized
override fun receive(stubMethod: StubMethod.Receive, args: Array): Any {
+ logger.d("Coordinator", "Receive method invoked")
stubMethod.argumentProcessor.inject(args)
val topic = stubMethod.argumentProcessor.getTopic()
@@ -70,18 +75,25 @@ internal class Coordinator(
}
override fun subscribe(stubMethod: StubMethod.Subscribe, args: Array): Any {
+ logger.d("Coordinator", "Subscribe method invoked")
stubMethod.argumentProcessor.inject(args)
val topic = stubMethod.argumentProcessor.getTopic()
- return client.subscribe(topic to stubMethod.qos)
+ val qos = stubMethod.qos
+ val status = client.subscribe(topic to qos)
+ logger.d("Coordinator", "Subscribing topic: $topic with qos: $qos")
+ return status
}
override fun subscribeWithStream(
stubMethod: StubMethod.SubscribeWithStream,
args: Array
): Any {
+ logger.d("Coordinator", "Subscribe method invoked with a returning stream")
stubMethod.argumentProcessor.inject(args)
val topic = stubMethod.argumentProcessor.getTopic()
- client.subscribe(topic to stubMethod.qos)
+ val qos = stubMethod.qos
+ client.subscribe(topic to qos)
+ logger.d("Coordinator", "Subscribing topic: $topic with qos: $qos")
val flowable = Flowable.create(
FlowableOnSubscribe { emitter ->
@@ -111,22 +123,28 @@ internal class Coordinator(
}
override fun unsubscribe(stubMethod: StubMethod.Unsubscribe, args: Array): Any {
+ logger.d("Coordinator", "Unsubscribe method invoked")
stubMethod.argumentProcessor.inject(args)
val topics = stubMethod.argumentProcessor.getTopics()
- return if (topics.size == 1) {
+ val status = if (topics.size == 1) {
client.unsubscribe(topics[0])
} else {
client.unsubscribe(topics[0], *topics.sliceArray(IntRange(1, topics.size - 1)))
}
+ logger.d("Coordinator", "Unsubscribing topics: $topics")
+ return status
}
override fun subscribeAll(stubMethod: StubMethod.SubscribeAll, args: Array): Any {
+ logger.d("Coordinator", "Subscribe method invoked for multiple topics")
val topicList = (args[0] as Map).toList()
- return if (topicList.size == 1) {
+ val status = if (topicList.size == 1) {
client.subscribe(topicList[0])
} else {
client.subscribe(topicList[0], *topicList.toTypedArray().sliceArray(IntRange(1, topicList.size - 1)))
}
+ logger.d("Coordinator", "Subscribing topics: $topicList")
+ return status
}
override fun getEventStream(): Stream {
From bb309e01ab0d9c189c45de1b80610fea6624cf9c Mon Sep 17 00:00:00 2001
From: deepanshu42
Date: Wed, 19 Apr 2023 11:08:50 +0530
Subject: [PATCH 24/25] Add empty service interface check
---
courier/src/main/java/com/gojek/courier/stub/StubInterface.kt | 1 +
1 file changed, 1 insertion(+)
diff --git a/courier/src/main/java/com/gojek/courier/stub/StubInterface.kt b/courier/src/main/java/com/gojek/courier/stub/StubInterface.kt
index a5a85261..35918cb6 100644
--- a/courier/src/main/java/com/gojek/courier/stub/StubInterface.kt
+++ b/courier/src/main/java/com/gojek/courier/stub/StubInterface.kt
@@ -60,6 +60,7 @@ internal class StubInterface(
private fun Class<*>.findStubMethods(): Map {
// Remove all default methods
val methods = declaredMethods.filterNot { runtimePlatform.isDefaultMethod(it) }
+ require(methods.isNotEmpty()) { "Service interface should have atleast one abstract method" }
val stubMethods = methods.mapNotNull { stubMethodFactory.create(it) }
return methods.zip(stubMethods).toMap()
}
From a418e75569384d85be46e5d72313e64a8d9c7ef0 Mon Sep 17 00:00:00 2001
From: deepanshu42
Date: Wed, 19 Apr 2023 11:11:36 +0530
Subject: [PATCH 25/25] Update proguard rules
---
proguard/proguard-rules.pro | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/proguard/proguard-rules.pro b/proguard/proguard-rules.pro
index 6e5c4b94..441b7447 100644
--- a/proguard/proguard-rules.pro
+++ b/proguard/proguard-rules.pro
@@ -137,4 +137,14 @@
public static int d(...);
public static int e(...);
}
-##---------------End: proguard configuration for android.Log----------
\ No newline at end of file
+##---------------End: proguard configuration for android.Log----------
+
+##---------------Begin: proguard configuration for courier annotations----------
+-keepclasseswithmembers class * {
+ @com.gojek.courier.annotation.* ;
+}
+-if interface * { @com.gojek.courier.annotation.* ; }
+-keepclassmembers,allowshrinking,allowobfuscation interface * {
+ @com.gojek.courier.annotation.* ;
+}
+##---------------End: proguard configuration for courier annotations----------
\ No newline at end of file