Description
my android app is going to be a server which allows a web to connect to it as a client . i have a SocketServerManger which handle the task properly when i connect to my android device via ws connection . but i want my clients can connect to the android device server with wss connection .
here is my manager :
`class SocketServerManger(port: Int, val socketListener: List, context: Context) :
WebSocketServer(InetSocketAddress(port)) {
var connection: WebSocket? = null
private val _isConnectionOpen = MutableStateFlow(false)
val isConnectionOpen: StateFlow<Boolean> = _isConnectionOpen
override fun onStart() {
println("WebSocket server started")
}
override fun onOpen(conn: WebSocket?, handshake: ClientHandshake?) {
connection = conn
socketListener.forEach { it.onConnected() }
}
override fun onClose(conn: WebSocket?, code: Int, reason: String?, remote: Boolean) {
socketListener.forEach { it.onDisconnected(code, reason) }
}
override fun onMessage(conn: WebSocket?, message: String?) {
socketListener.forEach { it.onMessage(conn, message) }
}
override fun onError(conn: WebSocket?, ex: Exception?) {
socketListener.forEach { it.onError(ex) }
ex?.printStackTrace()
}
suspend fun sendMessagesUntilSuccess(timeoutMillis: Long = 50000, message: String): Boolean {
var success = false
while (!success) {
serverLog(
"while (!success)",
"timeOutTag"
)
success = sendMessageWithTimeout(timeoutMillis, message)
if (!success) {
// Add a delay before retrying to avoid continuous retries and potential rate limiting
delay(1000)
}
}
return success
}
suspend fun sendMessageWithTimeout(timeoutMillis: Long = 5000, message: String): Boolean {
return withContext(Dispatchers.IO) {
return@withContext try {
withTimeout(timeoutMillis) {
val result = CoroutineScope(Dispatchers.IO).async {
try {
serverLog("sendMessageWithTimeout try : $message", "timeOutTag")
if (connection != null && connection!!.isOpen) {
connection!!.send(message)
true
} else {
false
}
} catch (e: org.java_websocket.exceptions.WebsocketNotConnectedException) {
socketListener.forEach { it.onException(e) }
false
}
}.await()
result
}
} catch (e: TimeoutCancellationException) {
socketListener.forEach { it.onException(e) }
false
} catch (e: Exception) {
socketListener.forEach { it.onException(e) }
false
}
}
}
fun isConnectionOpen() = connection?.isOpen ?: false
fun isPortAvailable(port: Int): Boolean {
return try {
ServerSocket(port).close()
true
} catch (e: IOException) {
false
}
}
}`
i add the below code to set up ssl/tls:
` init {
createSSLContext(context)?.let {
setWebSocketFactory(DefaultSSLWebSocketServerFactory(it))
}
}
private fun createSSLContext(context: Context): SSLContext? {
try {
val keystoreFileName = "keystore.jks"
val keystorePassword = "socket123"
val keystoreInputStream: InputStream = context.assets.open(keystoreFileName)
val keyStore = KeyStore.getInstance("JKS")
keyStore.load(keystoreInputStream, keystorePassword.toCharArray())
keystoreInputStream.close()
val keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
keyManagerFactory.init(keyStore, keystorePassword.toCharArray())
val sslContext = SSLContext.getInstance("TLS")
sslContext.init(keyManagerFactory.keyManagers, null, SecureRandom())
return sslContext
}catch (e : Exception){
serverLog("createSSLContext ${e.message}")
}
return null
}
`
but it keeps throwing the exception:
Caused by: java.security.KeyStoreException: java.security.NoSuchAlgorithmException: KeyStore JKS implementation not found
it throw it on this line :
val keyStore = KeyStore.getInstance("JKS")