p≡p for Java
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
12 KiB

3 years ago
7 years ago
7 years ago
3 years ago
3 years ago
3 years ago
3 years ago
1 year ago
3 years ago
7 years ago
  1. #include "foundation_pEp_jniadapter_AbstractEngine.h"
  2. #include <pEp/keymanagement.h>
  3. #include <pEp/message_api.h>
  4. #include <pEp/sync_api.h>
  5. #include <pEp/pEpLog.hh>
  6. #include <pEp/passphrase_cache.hh>
  7. #include <pEp/callback_dispatcher.hh>
  8. #include "throw_pEp_exception.hh"
  9. #include "jniutils.hh"
  10. #include "passphrase_callback.hh"
  11. namespace pEp {
  12. using namespace pEp::JNIAdapter;
  13. using namespace utility; // for libpEpAdapter locked queue impl. TODO:rename
  14. bool first = true;
  15. JavaVM *jvm= nullptr;
  16. std::mutex mutex_obj;
  17. jfieldID signal_field_value = nullptr;
  18. jfieldID passphrase_type_field_value = nullptr;
  19. jmethodID messageConstructorMethodID = nullptr;
  20. jmethodID messageToSendMethodID = nullptr;
  21. jmethodID notifyHandShakeMethodID = nullptr;
  22. jmethodID needsFastPollMethodID = nullptr;
  23. jmethodID passphraseRequiredMethodID = nullptr;
  24. jmethodID sync_handshake_signal_values = nullptr;
  25. jmethodID passphrase_status_values = nullptr;
  26. jmethodID passphrase_callback_values = nullptr;
  27. jobject objj = nullptr;
  28. jclass messageClass = nullptr;
  29. jclass identityClass = nullptr;
  30. jclass signalClass = nullptr;
  31. jclass abstractEngineClass = nullptr;
  32. jclass passphraseTypeClass = nullptr;
  33. namespace JNISync {
  34. JNIEnv* env() {
  35. JNIEnv *thread_env = nullptr;
  36. int status = jvm->GetEnv(reinterpret_cast<void**>(&thread_env), JNI_VERSION_1_6);
  37. if (status < 0) {
  38. #ifdef ANDROID
  39. status = jvm->AttachCurrentThread(&thread_env, nullptr);
  40. #else
  41. status = jvm->AttachCurrentThread(reinterpret_cast<void**>(&thread_env), nullptr);
  42. #endif
  43. }
  44. assert(status >= 0);
  45. return thread_env;
  46. }
  47. void onSyncStartup() {
  48. pEpLog("called");
  49. env();
  50. }
  51. void onSyncShutdown() {
  52. pEpLog("called");
  53. jvm->DetachCurrentThread();
  54. }
  55. };
  56. void jni_init() {
  57. JNIEnv * _env = JNISync::env();
  58. messageClass = static_cast<jclass>(_env->NewGlobalRef(findClass(_env, "foundation/pEp/jniadapter/Message")));
  59. identityClass = static_cast<jclass>(_env->NewGlobalRef(findClass(_env, "foundation/pEp/jniadapter/_Identity")));
  60. signalClass = static_cast<jclass>(_env->NewGlobalRef(findClass(_env, "foundation/pEp/jniadapter/SyncHandshakeSignal")));
  61. passphraseTypeClass = static_cast<jclass>(_env->NewGlobalRef(findClass(_env, "foundation/pEp/jniadapter/PassphraseType")));
  62. abstractEngineClass = static_cast<jclass>(_env->NewGlobalRef(findClass(_env, "foundation/pEp/jniadapter/AbstractEngine")));
  63. messageConstructorMethodID = _env->GetMethodID(
  64. messageClass,
  65. "<init>",
  66. "(J)V");
  67. messageToSendMethodID = _env->GetMethodID(
  68. abstractEngineClass,
  69. "messageToSendCallFromC",
  70. "(Lfoundation/pEp/jniadapter/Message;)I");
  71. needsFastPollMethodID = _env->GetMethodID(
  72. abstractEngineClass,
  73. "needsFastPollCallFromC",
  74. "(Z)I");
  75. notifyHandShakeMethodID = _env->GetMethodID(
  76. abstractEngineClass,
  77. "notifyHandshakeCallFromC",
  78. "(Lfoundation/pEp/jniadapter/_Identity;Lfoundation/pEp/jniadapter/_Identity;Lfoundation/pEp/jniadapter/SyncHandshakeSignal;)I");
  79. passphraseRequiredMethodID = _env->GetMethodID(
  80. abstractEngineClass,
  81. "passphraseRequiredFromC",
  82. "(Lfoundation/pEp/jniadapter/PassphraseType;)[B");
  83. sync_handshake_signal_values = JNISync::env()->GetStaticMethodID(
  84. signalClass,
  85. "values",
  86. "()[Lfoundation/pEp/jniadapter/SyncHandshakeSignal;");
  87. passphrase_status_values = JNISync::env()->GetStaticMethodID(
  88. passphraseTypeClass,
  89. "values",
  90. "()[Lfoundation/pEp/jniadapter/PassphraseType;");
  91. signal_field_value = JNISync::env()->GetFieldID(
  92. signalClass,
  93. "value",
  94. "I");
  95. passphrase_type_field_value = JNISync::env()->GetFieldID(passphraseTypeClass, "value", "I");
  96. }
  97. char* JNIAdapter::passphraseRequiredCallback(
  98. const PEP_STATUS status)
  99. {
  100. pEpLog("called");
  101. jobject status_ = nullptr;
  102. {
  103. assert(passphraseTypeClass);
  104. assert(passphrase_status_values);
  105. assert(passphrase_type_field_value);
  106. jobjectArray values = static_cast<jobjectArray>(JNISync::env()->CallStaticObjectMethod(passphraseTypeClass, passphrase_status_values));
  107. if (JNISync::env()->ExceptionCheck()) {
  108. JNISync::env()->ExceptionClear();
  109. throw_pEp_Exception(JNISync::env(), PEP_UNKNOWN_ERROR);
  110. }
  111. jsize values_size = JNISync::env()->GetArrayLength(values);
  112. for (jsize i = 0; i < values_size; i++) {
  113. jobject element = JNISync::env()->GetObjectArrayElement(values, i);
  114. assert(element);
  115. jint value = JNISync::env()->GetIntField(element, passphrase_type_field_value);
  116. if (value == static_cast<jint>(status)) {
  117. status_ = element;
  118. break;
  119. }
  120. JNISync::env()->DeleteLocalRef(element);
  121. }
  122. }
  123. assert(objj && passphraseRequiredMethodID);
  124. jobject ppJO = JNISync::env()->CallObjectMethod(objj, passphraseRequiredMethodID, status_);
  125. if (JNISync::env()->ExceptionCheck()) {
  126. JNISync::env()->ExceptionDescribe();
  127. JNISync::env()->ExceptionClear();
  128. }
  129. jbyteArray ppJBA = static_cast<jbyteArray>(ppJO);
  130. char* passphrase_ = to_string( JNISync::env(), ppJBA);
  131. return passphrase_;
  132. }
  133. PEP_STATUS messageToSend(message *msg)
  134. {
  135. std::lock_guard <std::mutex> l(mutex_obj);
  136. pEpLog("called");
  137. // Passphrase
  138. // When a protocol implementation of the p≡p engine using messageToSend() cannot sign or encrypt with an
  139. // empty passphrase and not with the configured passphrase it is calling messageToSend() with a NULL instead
  140. // of a struct _message object.
  141. if (Adapter::on_sync_thread() && !msg) {
  142. return pEp::PassphraseCache::config_next_passphrase();
  143. }
  144. // reset passphrase iterator
  145. if (Adapter::on_sync_thread()) {
  146. pEp::PassphraseCache::config_next_passphrase(true);
  147. }
  148. jobject msg_ = nullptr;
  149. assert(messageClass && messageConstructorMethodID && objj && messageToSendMethodID);
  150. msg_ = JNISync::env()->NewObject(messageClass, messageConstructorMethodID, reinterpret_cast<jlong>(msg));
  151. PEP_STATUS status = (PEP_STATUS) JNISync::env()->CallIntMethod(objj, messageToSendMethodID, msg_);
  152. if (JNISync::env()->ExceptionCheck()) {
  153. JNISync::env()->ExceptionDescribe();
  154. status = PEP_UNKNOWN_ERROR;
  155. JNISync::env()->ExceptionClear();
  156. }
  157. return status;
  158. }
  159. PEP_STATUS notifyHandshake(pEp_identity *me,
  160. pEp_identity *partner,
  161. sync_handshake_signal signal)
  162. {
  163. std::lock_guard<std::mutex> l(mutex_obj);
  164. pEpLog("called");
  165. jobject me_ = nullptr;
  166. jobject partner_ = nullptr;
  167. me_ = from_identity(JNISync::env(), me, identityClass);
  168. partner_ = from_identity(JNISync::env(), partner, identityClass);
  169. jobject signal_ = nullptr;
  170. {
  171. assert(signalClass);
  172. assert(sync_handshake_signal_values);
  173. assert(signal_field_value);
  174. jobjectArray values = static_cast<jobjectArray>(JNISync::env()->CallStaticObjectMethod(signalClass, sync_handshake_signal_values));
  175. if (JNISync::env()->ExceptionCheck()) {
  176. JNISync::env()->ExceptionClear();
  177. return PEP_UNKNOWN_ERROR;
  178. }
  179. jsize values_size = JNISync::env()->GetArrayLength(values);
  180. for (jsize i = 0; i < values_size; i++) {
  181. jobject element = JNISync::env()->GetObjectArrayElement(values, i);
  182. assert(element);
  183. jint value = JNISync::env()->GetIntField(element, signal_field_value);
  184. if (value == static_cast<jint>(signal)) {
  185. signal_ = element;
  186. break;
  187. }
  188. JNISync::env() -> DeleteLocalRef(element);
  189. }
  190. }
  191. assert(objj && notifyHandShakeMethodID);
  192. PEP_STATUS status = (PEP_STATUS) JNISync::env()->CallIntMethod(objj, notifyHandShakeMethodID, me_, partner_, signal_);
  193. if (JNISync::env()->ExceptionCheck()) {
  194. JNISync::env()->ExceptionClear();
  195. return PEP_UNKNOWN_ERROR;
  196. }
  197. return status;
  198. }
  199. }
  200. extern "C" {
  201. using namespace pEp;
  202. JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_init(JNIEnv *env,
  203. jobject obj)
  204. {
  205. std::lock_guard<std::mutex> l(global_mutex); // global mutex for write access to <unordered_map>
  206. pEpLog("called");
  207. if (first) {
  208. pEpLog("first Engine instance");
  209. first = false;
  210. env->GetJavaVM(&jvm);
  211. jni_init();
  212. objj = env->NewGlobalRef(obj);
  213. callback_dispatcher.add(messageToSend, notifyHandshake, JNISync::onSyncStartup, JNISync::onSyncShutdown);
  214. Adapter::_messageToSend = CallbackDispatcher::messageToSend;
  215. }
  216. create_engine_java_object_mutex(env, obj); // Create a mutex per java object
  217. Adapter::session();
  218. }
  219. JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine_release(JNIEnv *env,
  220. jobject obj)
  221. {
  222. std::lock_guard<std::mutex> l(global_mutex); // global mutex for write access to <unordered_map>
  223. pEpLog("called");
  224. release_engine_java_object_mutex(env, obj);
  225. Adapter::session(pEp::Adapter::release);
  226. }
  227. JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine__1setDebugLogEnabled(
  228. JNIEnv *env,
  229. jclass clazz,
  230. jboolean enabled)
  231. {
  232. Adapter::pEpLog::set_enabled(static_cast<bool>(enabled));
  233. }
  234. JNIEXPORT jboolean JNICALL Java_foundation_pEp_jniadapter_AbstractEngine__1getDebugLogEnabled(
  235. JNIEnv *env,
  236. jclass clazz
  237. )
  238. {
  239. return static_cast<jboolean>(Adapter::pEpLog::get_enabled());
  240. }
  241. JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine__1getVersion(JNIEnv *env,
  242. jobject obj)
  243. {
  244. std::mutex *mutex_local = nullptr;
  245. {
  246. std::lock_guard<std::mutex> l(global_mutex);
  247. pEpLog("called with lock_guard");
  248. mutex_local = get_engine_java_object_mutex(env, obj);
  249. }
  250. std::lock_guard<std::mutex> l(*mutex_local);
  251. return env->NewStringUTF(::get_engine_version());
  252. }
  253. JNIEXPORT jstring JNICALL Java_foundation_pEp_jniadapter_AbstractEngine__1getProtocolVersion(JNIEnv *env,
  254. jobject obj)
  255. {
  256. std::mutex *mutex_local = nullptr;
  257. {
  258. std::lock_guard<std::mutex> l(global_mutex);
  259. pEpLog("called with lock_guard");
  260. mutex_local = get_engine_java_object_mutex(env, obj);
  261. }
  262. std::lock_guard<std::mutex> l(*mutex_local);
  263. return env->NewStringUTF(::get_protocol_version());
  264. }
  265. int examine_identity(pEp_identity *ident,
  266. void *arg)
  267. {
  268. locked_queue < pEp_identity * > *queue = static_cast<locked_queue < pEp_identity * > * > (arg);
  269. queue->push_back(identity_dup(ident));
  270. return 0;
  271. }
  272. JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine__1startSync(JNIEnv *env,
  273. jobject obj)
  274. {
  275. std::mutex *mutex_local = nullptr;
  276. {
  277. std::lock_guard<std::mutex> l(global_mutex);
  278. pEpLog("called with lock_guard");
  279. mutex_local = get_engine_java_object_mutex(env, obj);
  280. }
  281. std::lock_guard<std::mutex> l(*mutex_local);
  282. try {
  283. CallbackDispatcher::start_sync();
  284. } catch (RuntimeError& ex) {
  285. throw_pEp_Exception(env, ex.status);
  286. return;
  287. }
  288. }
  289. JNIEXPORT void JNICALL Java_foundation_pEp_jniadapter_AbstractEngine__1stopSync(JNIEnv *env,
  290. jobject obj)
  291. {
  292. std::mutex *mutex_local = nullptr;
  293. {
  294. std::lock_guard<std::mutex> l(global_mutex);
  295. pEpLog("called with lock_guard");
  296. mutex_local = get_engine_java_object_mutex(env, obj);
  297. }
  298. std::lock_guard<std::mutex> l(*mutex_local);
  299. CallbackDispatcher::stop_sync();
  300. }
  301. JNIEXPORT jboolean JNICALL Java_foundation_pEp_jniadapter_AbstractEngine__1isSyncRunning(JNIEnv *env,
  302. jobject obj)
  303. {
  304. std::mutex *mutex_local = nullptr;
  305. {
  306. std::lock_guard<std::mutex> l(global_mutex);
  307. pEpLog("called with lock_guard");
  308. mutex_local = get_engine_java_object_mutex(env, obj);
  309. }
  310. std::lock_guard<std::mutex> l(*mutex_local);
  311. return static_cast<jboolean>(Adapter::is_sync_running());
  312. }
  313. } // extern "C"