Skip to content

Commit

Permalink
chore(#44): merge branch 'develop' into add error code
Browse files Browse the repository at this point in the history
  • Loading branch information
tilak-puli committed Apr 13, 2023
2 parents 113ddb1 + 5dd3f9b commit 7ad1b1e
Show file tree
Hide file tree
Showing 27 changed files with 388 additions and 183 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ const val MTU_HEADER_SIZE = 3
const val REQUEST_MTU_TIME_OUT = -1

class Controller(val context: Context) {
private lateinit var scanner: Scanner
private val logTag = getLogTag(javaClass.simpleName)

private var gattClient: GattClient? = null
private var scanner: Scanner? = null
private lateinit var messageSender: IMessageSender
private var requestedMTUValue = -1
private lateinit var mtuValues : Array<Int>
Expand All @@ -34,7 +34,7 @@ class Controller(val context: Context) {

fun scan(scanStartMessage: ScanStartMessage) {
scanner = Scanner(context)
scanner.start(
scanner?.start(
scanStartMessage.serviceUUID,
scanStartMessage.advPayload,
this::onDeviceFound,
Expand All @@ -43,7 +43,7 @@ class Controller(val context: Context) {
}

fun stopScan() {
scanner.stopScan()
scanner?.stopScan()
}

@SuppressLint("MissingPermission")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.mosip.tuvali.common.safeExecute

import io.mosip.tuvali.openid4vpble.exception.OpenIdBLEExceptionHandler

class TryExecuteSync(private val bleExceptionHandler: OpenIdBLEExceptionHandler) {
private val mutex = Object()

fun <T> run(fn: () -> T): T? {
var returnValue: T? = null;

synchronized(mutex) {
try {
returnValue = fn()
} catch (e: Exception) {
bleExceptionHandler.handleException(Exception("Unknown Exception", e))
}
}

return returnValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,21 @@ package io.mosip.tuvali.openid4vpble
import android.util.Log
import com.facebook.react.bridge.*
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter
import io.mosip.tuvali.verifier.Verifier
import io.mosip.tuvali.wallet.Wallet
import io.mosip.tuvali.common.safeExecute.TryExecuteSync
import io.mosip.tuvali.openid4vpble.exception.OpenIdBLEExceptionHandler
import io.mosip.tuvali.openid4vpble.exception.exception.BLEException
import io.mosip.tuvali.openid4vpble.exception.exception.ErrorCode
import io.mosip.tuvali.openid4vpble.exception.exception.UnknownException
import org.json.JSONObject
import io.mosip.tuvali.transfer.Util.Companion.getLogTag
import io.mosip.tuvali.verifier.Verifier
import io.mosip.tuvali.wallet.Wallet
import org.json.JSONObject

class Openid4vpBleModule(private val reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
private val logTag = getLogTag(javaClass.simpleName)
private var verifier: Verifier? = null
private var wallet: Wallet? = null
private val mutex = Object()
private var bleExceptionHandler = OpenIdBLEExceptionHandler(this::emitNearbyErrorEvent, this::stopBLE)

init {
Thread.setDefaultUncaughtExceptionHandler { _, exception ->
bleExceptionHandler.handleException(UnknownException("Unknown Exception", exception))
}
}
private val tryExecuteSync = TryExecuteSync(bleExceptionHandler);

//Inji contract requires double quotes around the states.
enum class VCResponseStates(val value: String) {
Expand Down Expand Up @@ -52,23 +45,31 @@ class Openid4vpBleModule(private val reactContext: ReactApplicationContext) :
@ReactMethod(isBlockingSynchronousMethod = true)
fun getConnectionParameters(): String {
Log.d(logTag, "getConnectionParameters new verifier object at ${System.nanoTime()}")
synchronized(mutex) {

return tryExecuteSync.run {
if (verifier == null) {
Log.d(logTag, "synchronized getConnectionParameters new verifier object at ${System.nanoTime()}")
verifier = Verifier(reactContext, this::emitNearbyMessage, this::emitNearbyEvent, this::onException)
verifier?.generateKeyPair()
}

val payload = verifier?.getAdvIdentifier("OVPMOSIP")
Log.d(
logTag,
"synchronized getConnectionParameters called with adv identifier $payload at ${System.nanoTime()} and verifier hashcode: ${verifier.hashCode()}"
)
return "{\"cid\":\"ilB8l\",\"pk\":\"${payload}\"}"
}

return@run "{\"cid\":\"ilB8l\",\"pk\":\"${payload}\"}"
}.orEmpty()
}

private fun onException(exception: BLEException){
bleExceptionHandler.handleException(exception)
private fun onException(exception: Throwable){
if(exception.cause != null){
Log.e(logTag, "Exception: ${exception.message}");
bleExceptionHandler.handleException(exception.cause!!)
} else {
bleExceptionHandler.handleException(exception)
}
}

@ReactMethod(isBlockingSynchronousMethod = true)
Expand All @@ -79,7 +80,8 @@ class Openid4vpBleModule(private val reactContext: ReactApplicationContext) :
@ReactMethod(isBlockingSynchronousMethod = true)
fun setConnectionParameters(params: String) {
Log.d(logTag, "setConnectionParameters at ${System.nanoTime()}")
synchronized(mutex) {

tryExecuteSync.run {
if (wallet == null) {
Log.d(logTag, "synchronized setConnectionParameters new wallet object at ${System.nanoTime()}")
wallet = Wallet(reactContext, this::emitNearbyMessage, this::emitNearbyEvent, this::onException)
Expand All @@ -97,8 +99,9 @@ class Openid4vpBleModule(private val reactContext: ReactApplicationContext) :
@ReactMethod
fun createConnection(mode: String, callback: Callback) {
Log.d(logTag, "createConnection: received request with mode $mode at ${System.nanoTime()}")
synchronized(mutex) {
Log.d(logTag, "synchronized createConnection: received request with mode $mode at ${System.nanoTime()}")

tryExecuteSync.run {
Log.d(logTag, "synchronized createConnection: received request with mode $mode at ${System.nanoTime()}")
when (mode) {
"advertiser" -> {
verifier?.startAdvertisement("OVPMOSIP", callback)
Expand All @@ -117,15 +120,15 @@ class Openid4vpBleModule(private val reactContext: ReactApplicationContext) :
fun destroyConnection(callback: Callback) {
//TODO: Make sure callback can be called only once[Can be done once wallet and verifier split into different modules]
Log.d(logTag, "destroyConnection called at ${System.nanoTime()}")

stopBLE(callback)
tryExecuteSync.run {
stopBLE(callback)
}
}

private fun stopBLE(callback: Callback) {
synchronized(mutex) {
if (wallet == null && verifier == null) {
if (wallet == null && verifier == null) {
callback()
} else {
} else {
if (wallet != null) {
Log.d(logTag, "synchronized destroyConnection called for wallet at ${System.nanoTime()}")
stopWallet { callback() }
Expand All @@ -135,7 +138,6 @@ class Openid4vpBleModule(private val reactContext: ReactApplicationContext) :
stopVerifier { callback() }
}
}
}
}

private fun stopVerifier(onDestroy: Callback) {
Expand Down Expand Up @@ -163,21 +165,27 @@ class Openid4vpBleModule(private val reactContext: ReactApplicationContext) :
@ReactMethod
fun send(message: String, callback: Callback) {
Log.d(logTag, "send: message $message at ${System.nanoTime()}")
val messageSplits = message.split("\n", limit = 2)
when (messageSplits[0]) {
NearbyEvents.EXCHANGE_RECEIVER_INFO.value -> {
callback()
}
NearbyEvents.EXCHANGE_SENDER_INFO.value -> {
callback()
wallet?.writeToIdentifyRequest()
}
NearbyEvents.SEND_VC.value -> {
callback()
wallet?.sendData(messageSplits[1])
}
NearbyEvents.SEND_VC_RESPONSE.value -> {
verifier?.notifyVerificationStatus(messageSplits[1] == VCResponseStates.ACCEPTED.value)

tryExecuteSync.run {
val messageSplits = message.split("\n", limit = 2)
when (messageSplits[0]) {
NearbyEvents.EXCHANGE_RECEIVER_INFO.value -> {
callback()
}
NearbyEvents.EXCHANGE_SENDER_INFO.value -> {
callback()
wallet?.writeToIdentifyRequest()
}
NearbyEvents.SEND_VC.value -> {
callback()
wallet?.sendData(messageSplits[1])
}
NearbyEvents.SEND_VC_RESPONSE.value -> {
verifier?.notifyVerificationStatus(messageSplits[1] == VCResponseStates.ACCEPTED.value)
}
else -> {
Log.d(logTag, "send: received send with unrecognized event")
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ class OpenIdBLEExceptionHandler(private val sendError: (String, ErrorCode) -> Un
}
}

stopBle {}
try{
stopBle {}
} catch (e: Exception) {
Log.d(logTag,"Failed to stop BLE connection while handling exception: $e")
}
}

private fun handleUnknownException(e: BLEException) {
Expand Down
26 changes: 15 additions & 11 deletions android/src/main/java/io/mosip/tuvali/transfer/Assembler.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package io.mosip.tuvali.transfer

import android.util.Log
import io.mosip.tuvali.transfer.Util.Companion.twoBytesToIntBigEndian
import io.mosip.tuvali.transfer.ByteCount.TwoBytes
import io.mosip.tuvali.transfer.Util.Companion.networkOrderedByteArrayToInt
import io.mosip.tuvali.verifier.exception.CorruptedChunkReceivedException
import io.mosip.tuvali.transfer.Util.Companion.getLogTag

class Assembler(private val totalSize: Int, private val maxDataBytes: Int ): ChunkerBase(maxDataBytes) {
class Assembler(totalSize: Int, private val maxDataBytes: Int ): ChunkerBase(maxDataBytes) {
private val logTag = getLogTag(javaClass.simpleName)
private var data: ByteArray = ByteArray(totalSize)
private var lastReadSeqNumber: Int? = null
Expand All @@ -16,6 +17,7 @@ class Assembler(private val totalSize: Int, private val maxDataBytes: Int ): Chu
init {
Log.i(logTag, "expected total chunk size: $totalSize")
if (totalSize == 0) {
//Todo: The exception name and the parameter doesn't makes sense
throw CorruptedChunkReceivedException(0, 0, 0)
}
}
Expand All @@ -25,8 +27,9 @@ class Assembler(private val totalSize: Int, private val maxDataBytes: Int ): Chu
Log.e(logTag, "received invalid chunk chunkSize: ${chunkData.size}, lastReadSeqNumber: $lastReadSeqNumber")
return 0
}
val seqNumberInMeta = twoBytesToIntBigEndian(chunkData.copyOfRange(0, 2))
val crcReceived = twoBytesToIntBigEndian(chunkData.copyOfRange(2,4)).toUShort()

val seqNumberInMeta: ChunkSeqNumber = networkOrderedByteArrayToInt(chunkData.copyOfRange(0, 2), TwoBytes)
val crcReceived = networkOrderedByteArrayToInt(chunkData.copyOfRange(2,4), TwoBytes).toUShort()

//Log.d(logTag, "received add chunk received chunkSize: ${chunkData.size}, seqNumberInMeta: $seqNumberInMeta")

Expand All @@ -38,8 +41,9 @@ class Assembler(private val totalSize: Int, private val maxDataBytes: Int ): Chu
return seqNumberInMeta
}
lastReadSeqNumber = seqNumberInMeta
System.arraycopy(chunkData, chunkMetaSize, data, seqNumberInMeta * effectivePayloadSize, (chunkData.size-chunkMetaSize))
chunkReceivedMarker[seqNumberInMeta] = chunkReceivedMarkerByte
val seqIndex = seqNumberInMeta.toSeqIndex()
System.arraycopy(chunkData, chunkMetaSize, data, seqIndex * effectivePayloadSize, (chunkData.size-chunkMetaSize))
chunkReceivedMarker[seqIndex] = chunkReceivedMarkerByte
//Log.d(logTag, "adding chunk complete at index(0-based): ${seqNumberInMeta}, received chunkSize: ${chunkData.size}")
return seqNumberInMeta
}
Expand All @@ -61,14 +65,14 @@ class Assembler(private val totalSize: Int, private val maxDataBytes: Int ): Chu
}

fun getMissedSequenceNumbers(): IntArray {
var missedSeqNumbers = intArrayOf()
chunkReceivedMarker.forEachIndexed() { i, elem ->
var missedSeqNumberList = intArrayOf()
chunkReceivedMarker.forEachIndexed() { missedChunkSeqIndex: ChunkSeqIndex, elem ->
if (elem != chunkReceivedMarkerByte) {
//Log.d(logTag, "getMissedSequenceNumbers: adding missed sequence number $i")
missedSeqNumbers += i
//Log.d(logTag, "getMissedSequenceNumbers: adding missed sequence number $missedChunkSeqIndex")
missedSeqNumberList += missedChunkSeqIndex.toSeqNumber()
}
}
return missedSeqNumbers
return missedSeqNumberList
}

fun data(): ByteArray {
Expand Down
39 changes: 22 additions & 17 deletions android/src/main/java/io/mosip/tuvali/transfer/Chunker.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package io.mosip.tuvali.transfer

import android.util.Log
import io.mosip.tuvali.transfer.Util.Companion.intToTwoBytesBigEndian
import io.mosip.tuvali.transfer.ByteCount.TwoBytes
import io.mosip.tuvali.transfer.Util.Companion.intToNetworkOrderedByteArray
import io.mosip.tuvali.transfer.Util.Companion.getLogTag

class Chunker(private val data: ByteArray, private val maxDataBytes: Int) :
Expand All @@ -14,35 +15,36 @@ class Chunker(private val data: ByteArray, private val maxDataBytes: Int) :

init {
Log.i(logTag, "Total number of chunks calculated: $totalChunkCount")
val startTime = System.currentTimeMillis()
// val startTime = System.currentTimeMillis()
for (idx in 0 until totalChunkCount) {
preSlicedChunks[idx] = chunk(idx)
}
//Log.d(logTag, "Chunks pre-populated in ${System.currentTimeMillis() - startTime} ms time")
}

fun next(): ByteArray {
val seqNumber = chunksReadCounter
chunksReadCounter++
return preSlicedChunks[seqNumber]!!
return preSlicedChunks[chunksReadCounter++]!!
}

fun chunkBySequenceNumber(num: Int): ByteArray {
return preSlicedChunks[num]!!
fun chunkBySequenceNumber(missedSeqNumber: ChunkSeqNumber): ByteArray {
return preSlicedChunks[missedSeqNumber.toSeqIndex()]!!
}

private fun chunk(seqNumber: Int): ByteArray {
val fromIndex = seqNumber * effectivePayloadSize

return if (seqNumber == (totalChunkCount - 1).toInt() && lastChunkByteCount > 0) {
Log.d(logTag, "fetching last chunk")
frameChunk(seqNumber, fromIndex, fromIndex + lastChunkByteCount)
private fun chunk(seqIndex: ChunkSeqIndex): ByteArray {
val fromIndex = seqIndex * effectivePayloadSize
return if (isLastChunkSmallerSize(seqIndex)) {
frameChunk(seqIndex.toSeqNumber(), fromIndex, fromIndex + lastChunkByteCount)
} else {
val toIndex = (seqNumber + 1) * effectivePayloadSize
frameChunk(seqNumber, fromIndex, toIndex)
val toIndex = fromIndex + effectivePayloadSize
frameChunk(seqIndex.toSeqNumber(), fromIndex, toIndex)
}
}

private fun isLastChunkSmallerSize(seqIndex: Int) =
isLastChunkIndex(seqIndex) && lastChunkByteCount > 0

private fun isLastChunkIndex(seqIndex: Int) = seqIndex == (totalChunkCount - 1)

/*
<--------------------------------------------------Max Data Bytes -------------------------------------------------------------->
+-----------------------+-----------------------------+-------------------------------------------------------------------------+
Expand All @@ -57,11 +59,14 @@ class Chunker(private val data: ByteArray, private val maxDataBytes: Int) :
val dataChunk = data.copyOfRange(fromIndex, toIndex)
val crc = CheckValue.get(dataChunk)

return intToTwoBytesBigEndian(seqNumber) + intToTwoBytesBigEndian(crc.toInt()) + dataChunk

return intToNetworkOrderedByteArray(seqNumber, TwoBytes) + intToNetworkOrderedByteArray(crc.toInt(), TwoBytes) + dataChunk

}

fun isComplete(): Boolean {
val isComplete = chunksReadCounter > (totalChunkCount - 1).toInt()
Log.i(logTag,"chunksReadCounter: $chunksReadCounter")
val isComplete = chunksReadCounter >= totalChunkCount
if (isComplete) {
Log.d(
logTag,
Expand Down
11 changes: 11 additions & 0 deletions android/src/main/java/io/mosip/tuvali/transfer/ChunkerBase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ package io.mosip.tuvali.transfer

import kotlin.math.ceil

typealias ChunkSeqIndex = Int
typealias ChunkSeqNumber = Int

fun ChunkSeqIndex.toSeqNumber(): ChunkSeqNumber {
return this + 1
}

fun ChunkSeqNumber.toSeqIndex(): ChunkSeqIndex {
return this - 1
}

open class ChunkerBase(maxDataBytes: Int) {
private val seqNumberReservedByteSize = 2
private val crcChecksumValueByteSize = 2
Expand Down
Loading

0 comments on commit 7ad1b1e

Please sign in to comment.