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.

286 lines
7.7 KiB

  1. //
  2. // PEPSync.m
  3. // pEpObjCAdapter
  4. //
  5. // Created by Dirk Zimmermann on 04.10.18.
  6. // Copyright © 2018 pp. All rights reserved.
  7. //
  8. #import <os/log.h>
  9. #import "PEPSync.h"
  10. #import "pEpEngine.h"
  11. #import "PEPSendMessageDelegate.h"
  12. #import "PEPNotifyHandshakeDelegate.h"
  13. #import "PEPMessageUtil.h"
  14. #import "PEPMessage.h"
  15. #import "PEPQueue.h"
  16. #import "PEPObjCAdapter.h"
  17. #import "NSError+PEP+Internal.h"
  18. #import "PEPSessionProvider.h"
  19. #import "PEPInternalSession.h"
  20. // MARK: - Internals
  21. static os_log_t s_logger;
  22. typedef PEP_STATUS (* t_messageToSendCallback)(struct _message *msg);
  23. typedef int (* t_injectSyncCallback)(SYNC_EVENT ev, void *management);
  24. @interface PEPSync ()
  25. + (PEPSync * _Nullable)instance;
  26. @property (nonatomic, nonnull) PEPQueue *queue;
  27. @property (nonatomic, nullable) NSThread *syncThread;
  28. @property (nonatomic, nullable) NSConditionLock *conditionLockForJoiningSyncThread;
  29. /**
  30. @Return: The callback for message sending that should be used on every session init.
  31. */
  32. + (t_messageToSendCallback)messageToSendCallback;
  33. /**
  34. @Return: The callback for injectiong sync messages that should be used on every session init.
  35. */
  36. + (t_injectSyncCallback)injectSyncCallback;
  37. - (PEP_STATUS)messageToSend:(struct _message *)msg;
  38. - (int)injectSyncEvent:(SYNC_EVENT)event;
  39. - (PEP_STATUS)notifyHandshake:(pEp_identity *)me
  40. partner:(pEp_identity *)partner
  41. signal:(sync_handshake_signal)signal;
  42. - (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold;
  43. @end
  44. // MARK: - Callbacks called by the engine, used in session init
  45. static PEP_STATUS s_messageToSendObjc(struct _message *msg)
  46. {
  47. PEPSync *pEpSync = [PEPSync instance];
  48. if (pEpSync) {
  49. return [pEpSync messageToSend:msg];
  50. } else {
  51. return PEP_SYNC_NO_NOTIFY_CALLBACK;
  52. }
  53. }
  54. static int s_inject_sync_event(SYNC_EVENT ev, void *management)
  55. {
  56. PEPSync *pEpSync = [PEPSync instance];
  57. if (pEpSync) {
  58. return [pEpSync injectSyncEvent:ev];
  59. } else {
  60. return 1;
  61. }
  62. }
  63. // MARK: - Callbacks called by the engine, used in register_sync_callbacks
  64. static PEP_STATUS s_notifyHandshake(pEp_identity *me,
  65. pEp_identity *partner,
  66. sync_handshake_signal signal)
  67. {
  68. PEPSync *pEpSync = [PEPSync instance];
  69. if (pEpSync) {
  70. return [pEpSync notifyHandshake:me partner:partner signal:signal];
  71. } else {
  72. return PEP_SYNC_NO_NOTIFY_CALLBACK;
  73. }
  74. }
  75. static SYNC_EVENT s_retrieve_next_sync_event(void *management, unsigned threshold)
  76. {
  77. PEPSync *sync = [PEPSync instance];
  78. return [sync retrieveNextSyncEvent:threshold];
  79. }
  80. // MARK: - Internal globals
  81. static __weak PEPSync *s_pEpSync;
  82. // MARK: - Public PEPSync class
  83. @implementation PEPSync
  84. + (t_messageToSendCallback)messageToSendCallback
  85. {
  86. return s_messageToSendObjc;
  87. }
  88. + (t_injectSyncCallback)injectSyncCallback
  89. {
  90. return s_inject_sync_event;
  91. }
  92. + (PEP_SESSION)createSession:(NSError **)error
  93. {
  94. PEP_SESSION session = NULL;
  95. PEP_STATUS status = init(&session,
  96. [PEPSync messageToSendCallback],
  97. [PEPSync injectSyncCallback]);
  98. if (status != PEP_STATUS_OK) {
  99. if (error) {
  100. *error = [NSError errorWithPEPStatusInternal:status];
  101. os_log(s_logger, "error creating session: %{public}@", *error);
  102. }
  103. return nil;
  104. }
  105. return session;
  106. }
  107. - (instancetype)initWithSendMessageDelegate:(id<PEPSendMessageDelegate>
  108. _Nullable)sendMessageDelegate
  109. notifyHandshakeDelegate:(id<PEPNotifyHandshakeDelegate>
  110. _Nullable)notifyHandshakeDelegate
  111. {
  112. if (self = [super init]) {
  113. _sendMessageDelegate = sendMessageDelegate;
  114. _notifyHandshakeDelegate = notifyHandshakeDelegate;
  115. _queue = [PEPQueue new];
  116. s_pEpSync = self;
  117. }
  118. return self;
  119. }
  120. - (void)startup
  121. {
  122. // Make sure queue is empty when we start.
  123. [self.queue removeAllObjects];
  124. [self assureMainSessionExists];
  125. self.conditionLockForJoiningSyncThread = [[NSConditionLock alloc] initWithCondition:NO];
  126. NSThread *theSyncThread = [[NSThread alloc] initWithTarget:self
  127. selector:@selector(syncThreadLoop:)
  128. object:nil];
  129. theSyncThread.name = @"pEp-sync-loop";
  130. self.syncThread = theSyncThread;
  131. [theSyncThread start];
  132. }
  133. - (void)shutdown
  134. {
  135. if (self.syncThread) {
  136. [self injectSyncEvent:nil];
  137. }
  138. }
  139. // MARK: - Private
  140. + (void)initialize
  141. {
  142. s_logger = os_log_create("security.pEp.adapter", "PEPSync");
  143. }
  144. + (PEPSync * _Nullable)instance
  145. {
  146. return s_pEpSync;
  147. }
  148. - (void)assureMainSessionExists
  149. {
  150. PEPInternalSession *session __attribute__((unused)) = [PEPSessionProvider session];
  151. }
  152. - (void)syncThreadLoop:(id)object
  153. {
  154. [self.conditionLockForJoiningSyncThread lock];
  155. os_log(s_logger, "trying to start the sync loop");
  156. PEPInternalSession *session = [PEPSessionProvider session];
  157. if (session) {
  158. PEP_STATUS status = register_sync_callbacks(session.session, nil, s_notifyHandshake,
  159. s_retrieve_next_sync_event);
  160. if (status == PEP_STATUS_OK) {
  161. status = do_sync_protocol(session.session, nil);
  162. if (status != PEP_STATUS_OK) {
  163. os_log_error(s_logger, "do_sync_protocol returned PEP_STATUS %d", status);
  164. os_log(s_logger, "sync loop is NOT running");
  165. }
  166. unregister_sync_callbacks(session.session);
  167. } else {
  168. os_log_error(s_logger, "register_sync_callbacks returned PEP_STATUS %d", status);
  169. os_log(s_logger, "sync loop is NOT running");
  170. }
  171. } else {
  172. os_log_error(s_logger, "could not create session for starting the sync loop");
  173. }
  174. os_log(s_logger, "sync loop finished");
  175. session = nil;
  176. [self.conditionLockForJoiningSyncThread unlockWithCondition:YES];
  177. }
  178. - (PEP_STATUS)messageToSend:(struct _message *)msg
  179. {
  180. if (self.sendMessageDelegate) {
  181. PEPMessage *theMessage = pEpMessageFromStruct(msg);
  182. return (PEP_STATUS) [self.sendMessageDelegate sendMessage:theMessage];
  183. } else {
  184. return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
  185. }
  186. }
  187. - (int)injectSyncEvent:(SYNC_EVENT)event
  188. {
  189. NSValue *value = [NSValue valueWithBytes:&event objCType:@encode(SYNC_EVENT)];
  190. if (event) {
  191. [self.queue enqueue:value];
  192. } else {
  193. [self.queue prequeue:value];
  194. [self.conditionLockForJoiningSyncThread lockWhenCondition:YES];
  195. [self.conditionLockForJoiningSyncThread unlock];
  196. self.conditionLockForJoiningSyncThread = nil;
  197. }
  198. return 0;
  199. }
  200. - (PEP_STATUS)notifyHandshake:(pEp_identity *)me
  201. partner:(pEp_identity *)partner
  202. signal:(sync_handshake_signal)signal
  203. {
  204. if (self.notifyHandshakeDelegate) {
  205. PEPIdentity *meIdentity = PEP_identityFromStruct(me);
  206. PEPIdentity *partnerIdentity = PEP_identityFromStruct(partner);
  207. return (PEP_STATUS) [self.notifyHandshakeDelegate
  208. notifyHandshake:NULL
  209. me:meIdentity
  210. partner:partnerIdentity
  211. signal:(PEPSyncHandshakeSignal) signal];
  212. } else {
  213. return PEP_SYNC_NO_NOTIFY_CALLBACK;
  214. }
  215. }
  216. - (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold
  217. {
  218. NSValue *value = [self.queue timedDequeue:&threshold];
  219. if (value) {
  220. SYNC_EVENT event;
  221. [value getValue:&event];
  222. return event;
  223. } else {
  224. return new_sync_timeout_event();
  225. }
  226. }
  227. @end