/** * JNI bridge between Kotlin/Java and libquicproquo_ffi. * * Compile with: * gcc -shared -fPIC -o libquicproquo_jni.so \ * -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" \ * dev_quicproquo_NativeBridge.c \ * -L ../../../../target/release -lquicproquo_ffi */ #include #include #include /* Forward declarations for libquicproquo_ffi functions. */ typedef struct QpqHandle QpqHandle; extern QpqHandle* qpq_connect(const char* server, const char* ca_cert, const char* server_name); extern int qpq_login(QpqHandle* handle, const char* username, const char* password); extern int qpq_send(QpqHandle* handle, const char* recipient, const uint8_t* message, size_t message_len); extern int qpq_receive(QpqHandle* handle, uint32_t timeout_ms, char** out_json); extern void qpq_disconnect(QpqHandle* handle); extern const char* qpq_last_error(const QpqHandle* handle); extern void qpq_free_string(char* ptr); /* --- JNI exports --- */ JNIEXPORT jlong JNICALL Java_dev_quicproquo_NativeBridge_nativeConnect( JNIEnv* env, jclass cls, jstring server, jstring caCert, jstring serverName) { const char* s = (*env)->GetStringUTFChars(env, server, NULL); const char* c = (*env)->GetStringUTFChars(env, caCert, NULL); const char* n = (*env)->GetStringUTFChars(env, serverName, NULL); QpqHandle* h = qpq_connect(s, c, n); (*env)->ReleaseStringUTFChars(env, server, s); (*env)->ReleaseStringUTFChars(env, caCert, c); (*env)->ReleaseStringUTFChars(env, serverName, n); return (jlong)(uintptr_t)h; } JNIEXPORT jint JNICALL Java_dev_quicproquo_NativeBridge_nativeLogin( JNIEnv* env, jclass cls, jlong handle, jstring username, jstring password) { QpqHandle* h = (QpqHandle*)(uintptr_t)handle; const char* u = (*env)->GetStringUTFChars(env, username, NULL); const char* p = (*env)->GetStringUTFChars(env, password, NULL); int code = qpq_login(h, u, p); (*env)->ReleaseStringUTFChars(env, username, u); (*env)->ReleaseStringUTFChars(env, password, p); return code; } JNIEXPORT jint JNICALL Java_dev_quicproquo_NativeBridge_nativeSend( JNIEnv* env, jclass cls, jlong handle, jstring recipient, jbyteArray message) { QpqHandle* h = (QpqHandle*)(uintptr_t)handle; const char* r = (*env)->GetStringUTFChars(env, recipient, NULL); jsize len = (*env)->GetArrayLength(env, message); jbyte* bytes = (*env)->GetByteArrayElements(env, message, NULL); int code = qpq_send(h, r, (const uint8_t*)bytes, (size_t)len); (*env)->ReleaseByteArrayElements(env, message, bytes, JNI_ABORT); (*env)->ReleaseStringUTFChars(env, recipient, r); return code; } JNIEXPORT jstring JNICALL Java_dev_quicproquo_NativeBridge_nativeReceive( JNIEnv* env, jclass cls, jlong handle, jint timeoutMs) { QpqHandle* h = (QpqHandle*)(uintptr_t)handle; char* json = NULL; int code = qpq_receive(h, (uint32_t)timeoutMs, &json); if (code != 0 || json == NULL) { if (json) qpq_free_string(json); return NULL; } jstring result = (*env)->NewStringUTF(env, json); qpq_free_string(json); return result; } JNIEXPORT void JNICALL Java_dev_quicproquo_NativeBridge_nativeDisconnect( JNIEnv* env, jclass cls, jlong handle) { QpqHandle* h = (QpqHandle*)(uintptr_t)handle; if (h) { qpq_disconnect(h); } } JNIEXPORT jstring JNICALL Java_dev_quicproquo_NativeBridge_nativeLastError( JNIEnv* env, jclass cls, jlong handle) { QpqHandle* h = (QpqHandle*)(uintptr_t)handle; const char* err = qpq_last_error(h); if (!err) return NULL; return (*env)->NewStringUTF(env, err); }