C++11 library providing functionality common to all adapters.
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.

248 lines
7.4 KiB

3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
  1. // This file is under GNU General Public License 3.0
  2. // see LICENSE.txt
  3. #include "Adapter.hh"
  4. #include <sstream>
  5. #include <iomanip>
  6. #include <assert.h>
  7. #include "status_to_string.hh"
  8. #include "pEpLog.hh"
  9. #include "passphrase_cache.hh"
  10. using namespace std;
  11. thread_local pEp::Adapter::Session pEp::Adapter::session;
  12. namespace pEp {
  13. void throw_status(::PEP_STATUS status)
  14. {
  15. if (status == ::PEP_STATUS_OK) {
  16. return;
  17. }
  18. if (status >= 0x400 && status <= 0x4ff) {
  19. return;
  20. }
  21. if (status == ::PEP_STATEMACHINE_CANNOT_SEND) {
  22. return;
  23. }
  24. if (status == ::PEP_OUT_OF_MEMORY) {
  25. throw bad_alloc();
  26. }
  27. if (status == ::PEP_ILLEGAL_VALUE) {
  28. throw invalid_argument("illegal value");
  29. }
  30. string _status = status_to_string(status);
  31. throw RuntimeError(_status, status);
  32. }
  33. RuntimeError::RuntimeError(const std::string &_text, ::PEP_STATUS _status)
  34. : std::runtime_error(_text.c_str()), text(_text), status(_status)
  35. {
  36. }
  37. namespace Adapter {
  38. // private
  39. SyncModes _sync_mode = SyncModes::Async;
  40. ::messageToSend_t _messageToSend = nullptr;
  41. ::notifyHandshake_t _notifyHandshake = nullptr;
  42. bool _adapter_manages_sync_thread = false;
  43. ::inject_sync_event_t _inject_action = _inject_sync_event;
  44. std::thread _sync_thread;
  45. ::utility::locked_queue<SYNC_EVENT, ::free_Sync_event> sync_evt_q;
  46. std::mutex mut;
  47. // private
  48. std::thread::id sync_thread_id()
  49. {
  50. return _sync_thread.get_id();
  51. }
  52. // public
  53. void sync_initialize(
  54. SyncModes mode,
  55. ::messageToSend_t messageToSend,
  56. ::notifyHandshake_t notifyHandshake,
  57. bool adapter_manages_sync_thread)
  58. {
  59. _messageToSend = messageToSend;
  60. _notifyHandshake = notifyHandshake;
  61. _adapter_manages_sync_thread = adapter_manages_sync_thread;
  62. set_sync_mode(mode);
  63. return;
  64. }
  65. // public
  66. void set_sync_mode(SyncModes mode)
  67. {
  68. // std::lock_guard<mutex> lock(mut);
  69. _sync_mode = mode;
  70. if (_sync_mode == SyncModes::Sync) {
  71. // init session with inject_sync = process
  72. // stop sync
  73. session(release);
  74. _inject_action = _process_sync_event;
  75. session(init);
  76. ::register_sync_callbacks(session(), nullptr, _notifyHandshake, _retrieve_next_sync_event);
  77. if(!_adapter_manages_sync_thread) {
  78. shutdown();
  79. } else {
  80. // The adapter need to shutdown sync thread
  81. }
  82. }
  83. if (_sync_mode == SyncModes::Async) {
  84. // init session with inject_sync = queue
  85. // start sync thread
  86. session(release);
  87. _inject_action = _inject_sync_event;
  88. session(init);
  89. if(!_adapter_manages_sync_thread) {
  90. if (!is_sync_running()) {
  91. startup<void>(_messageToSend, _notifyHandshake, nullptr, nullptr);
  92. }
  93. } else {
  94. // The adapter need to do sync thread start up
  95. }
  96. }
  97. if (_sync_mode == SyncModes::Off) {
  98. // init sesssion with inject_sync = null
  99. // stop sync thread
  100. if(!_adapter_manages_sync_thread) {
  101. shutdown();
  102. } else {
  103. // Adapter needs to shutdown sync thread
  104. }
  105. session(release);
  106. _inject_action = _inject_sync_event;
  107. session(init);
  108. }
  109. return;
  110. }
  111. // private
  112. int _process_sync_event(::SYNC_EVENT ev, void *management)
  113. {
  114. if (ev != nullptr) {
  115. ::do_sync_protocol_step(session(), nullptr, ev);
  116. return 0;
  117. } else {
  118. return 0;
  119. }
  120. }
  121. // public (json adapter needs it, but should use Session mgmt from libpEpAdapter eventually)
  122. int _inject_sync_event(::SYNC_EVENT ev, void *management)
  123. {
  124. try {
  125. if (ev == nullptr) {
  126. sync_evt_q.clear();
  127. sync_evt_q.push_back(ev);
  128. } else {
  129. sync_evt_q.push_front(ev);
  130. }
  131. } catch (exception &) {
  132. return 1;
  133. }
  134. return 0;
  135. }
  136. // private
  137. PEP_STATUS _ensure_passphrase(::PEP_SESSION session, const char *fpr)
  138. {
  139. return passphrase_cache.ensure_passphrase(session, fpr);
  140. }
  141. // public
  142. ::SYNC_EVENT _retrieve_next_sync_event(void *management, unsigned threshold)
  143. {
  144. ::SYNC_EVENT syncEvent = nullptr;
  145. const bool success = sync_evt_q.try_pop_front(syncEvent, std::chrono::seconds(threshold));
  146. if (!success) {
  147. return ::new_sync_timeout_event();
  148. }
  149. return syncEvent;
  150. }
  151. // public
  152. bool on_sync_thread()
  153. {
  154. return _sync_thread.get_id() == this_thread::get_id();
  155. }
  156. // public
  157. ::PEP_SESSION Session::operator()(session_action action)
  158. {
  159. std::lock_guard<mutex> lock(mut);
  160. ::PEP_STATUS status = ::PEP_STATUS_OK;
  161. switch (action) {
  162. case release:
  163. if (_session.get()) {
  164. _session = nullptr;
  165. }
  166. break;
  167. case init:
  168. if (!_session.get()) {
  169. ::PEP_SESSION session_;
  170. status = ::init(&session_, _messageToSend, _inject_action, _ensure_passphrase);
  171. throw_status(status);
  172. _session = SessionPtr{session_, ::release};
  173. }
  174. break;
  175. default:
  176. status = ::PEP_ILLEGAL_VALUE;
  177. }
  178. throw_status(status);
  179. return _session.get();
  180. }
  181. // public
  182. void inject_sync_shutdown() {
  183. pEpLog("called");
  184. _inject_sync_event(nullptr, nullptr);
  185. }
  186. // public
  187. void shutdown()
  188. {
  189. pEpLog("called");
  190. if (_sync_thread.joinable()) {
  191. pEpLog("sync_is_running - injecting null event");
  192. inject_sync_shutdown();
  193. _sync_thread.join();
  194. }
  195. }
  196. // public
  197. bool is_sync_running()
  198. {
  199. if(!_adapter_manages_sync_thread) {
  200. return _sync_thread.joinable();
  201. } else {
  202. return false;
  203. }
  204. }
  205. // public
  206. // Works even if adapter is managing sync thread, BUT must be using this queue
  207. bool in_shutdown()
  208. {
  209. SYNC_EVENT ev;
  210. try {
  211. ev = sync_evt_q.back();
  212. } catch (std::underflow_error &) {
  213. return false;
  214. }
  215. if (ev) {
  216. return false;
  217. } else {
  218. return true;
  219. }
  220. }
  221. } // namespace Adapter
  222. } // namespace pEp