pEpObjCAdapter/PEPSync.m
author Dirk Zimmermann <dz@pep.security>
Fri, 15 Mar 2019 16:01:34 +0100
branchIOS-1480
changeset 876 0899b80e06e7
parent 831 32f7a0c78c10
child 897 a1c583ffca0e
child 902 32760267cd59
permissions -rw-r--r--
IOS-1480 Import the framework version of PEPMessage.
     1 //
     2 //  PEPSync.m
     3 //  pEpObjCAdapter
     4 //
     5 //  Created by Dirk Zimmermann on 04.10.18.
     6 //  Copyright © 2018 p≡p. All rights reserved.
     7 //
     8 
     9 #import "PEPSync.h"
    10 
    11 #import "PEPSendMessageDelegate.h"
    12 #import "PEPNotifyHandshakeDelegate.h"
    13 #import "PEPMessageUtil.h"
    14 #import <PEPObjCAdapterFramework/PEPMessage.h>
    15 #import "PEPQueue.h"
    16 #import "PEPLock.h"
    17 #import "PEPObjCAdapter.h"
    18 #import "NSError+PEP+Internal.h"
    19 #import "PEPSessionProvider.h"
    20 #import "PEPInternalSession.h"
    21 
    22 // MARK: - Declare internals
    23 
    24 typedef PEP_STATUS (* t_messageToSendCallback)(struct _message *msg);
    25 typedef int (* t_injectSyncCallback)(SYNC_EVENT ev, void *management);
    26 
    27 @interface PEPSync ()
    28 
    29 + (PEPSync * _Nullable)instance;
    30 
    31 @property (nonatomic, nullable, weak) id<PEPSendMessageDelegate> sendMessageDelegate;
    32 @property (nonatomic, nullable, weak) id<PEPNotifyHandshakeDelegate> notifyHandshakeDelegate;
    33 @property (nonatomic, nonnull) PEPQueue *queue;
    34 @property (nonatomic, nullable) NSThread *syncThread;
    35 @property (nonatomic, nullable) NSConditionLock *conditionLockForJoiningSyncThread;
    36 
    37 /**
    38  @Return: The callback for message sending that should be used on every session init.
    39  */
    40 + (t_messageToSendCallback)messageToSendCallback;
    41 
    42 /**
    43  @Return: The callback for injectiong sync messages that should be used on every session init.
    44  */
    45 + (t_injectSyncCallback)injectSyncCallback;
    46 
    47 - (PEP_STATUS)messageToSend:(struct _message *)msg;
    48 
    49 - (int)injectSyncEvent:(SYNC_EVENT)event;
    50 
    51 - (PEP_STATUS)notifyHandshake:(pEp_identity *)me
    52                       partner:(pEp_identity *)partner
    53                        signal:(sync_handshake_signal)signal;
    54 
    55 - (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold;
    56 
    57 @end
    58 
    59 // MARK: - Callbacks called by the engine, used in session init
    60 
    61 static PEP_STATUS s_messageToSendObjc(struct _message *msg)
    62 {
    63     PEPSync *pEpSync = [PEPSync instance];
    64 
    65     if (pEpSync) {
    66         return [pEpSync messageToSend:msg];
    67     } else {
    68         return PEP_SYNC_NO_NOTIFY_CALLBACK;
    69     }
    70 }
    71 
    72 static int s_inject_sync_event(SYNC_EVENT ev, void *management)
    73 {
    74     PEPSync *pEpSync = [PEPSync instance];
    75 
    76     if (pEpSync) {
    77         return [pEpSync injectSyncEvent:ev];
    78     } else {
    79         return 1;
    80     }
    81 }
    82 
    83 // MARK: - Callbacks called by the engine, used in register_sync_callbacks
    84 
    85 static PEP_STATUS s_notifyHandshake(pEp_identity *me,
    86                                     pEp_identity *partner,
    87                                     sync_handshake_signal signal)
    88 {
    89     PEPSync *pEpSync = [PEPSync instance];
    90 
    91     if (pEpSync) {
    92         return [pEpSync notifyHandshake:me partner:partner signal:signal];
    93     } else {
    94         return PEP_SYNC_NO_NOTIFY_CALLBACK;
    95     }
    96 }
    97 
    98 static SYNC_EVENT s_retrieve_next_sync_event(void *management, unsigned threshold)
    99 {
   100     PEPSync *sync = [PEPSync instance];
   101     return [sync retrieveNextSyncEvent:threshold];
   102 }
   103 
   104 // MARK: - Internal globals
   105 
   106 static __weak PEPSync *s_pEpSync;
   107 
   108 // MARK: - Public PEPSync class
   109 
   110 @implementation PEPSync
   111 
   112 + (t_messageToSendCallback)messageToSendCallback
   113 {
   114     return s_messageToSendObjc;
   115 }
   116 
   117 + (t_injectSyncCallback)injectSyncCallback
   118 {
   119     return s_inject_sync_event;
   120 }
   121 
   122 + (PEP_SESSION)createSession:(NSError **)error
   123 {
   124     PEP_SESSION session = NULL;
   125 
   126     [PEPLock lockWrite];
   127     PEP_STATUS status = init(&session,
   128                              [PEPSync messageToSendCallback],
   129                              [PEPSync injectSyncCallback]);
   130     [PEPLock unlockWrite];
   131 
   132     if (status != PEP_STATUS_OK) {
   133         if (error) {
   134             *error = [NSError errorWithPEPStatusInternal:status];
   135         }
   136         return nil;
   137     }
   138 
   139     return session;
   140 }
   141 
   142 + (void)releaseSession:(PEP_SESSION)session
   143 {
   144     [PEPLock lockWrite];
   145     release(session);
   146     [PEPLock unlockWrite];
   147 }
   148 
   149 - (instancetype)initWithSendMessageDelegate:(id<PEPSendMessageDelegate>
   150                                              _Nonnull)sendMessageDelegate
   151                     notifyHandshakeDelegate:(id<PEPNotifyHandshakeDelegate>
   152                                              _Nonnull)notifyHandshakeDelegate
   153 {
   154     if (self = [super init]) {
   155         _sendMessageDelegate = sendMessageDelegate;
   156         _notifyHandshakeDelegate = notifyHandshakeDelegate;
   157         _queue = [PEPQueue new];
   158         s_pEpSync = self;
   159     }
   160     return self;
   161 }
   162 
   163 - (void)startup
   164 {
   165     // assure the main session exists
   166     PEPInternalSession *session = [PEPSessionProvider session];
   167     session = nil;
   168 
   169     self.conditionLockForJoiningSyncThread = [[NSConditionLock alloc] initWithCondition:NO];
   170     NSThread *theSyncThread = [[NSThread alloc] initWithTarget:self
   171                                                       selector:@selector(syncThreadLoop:)
   172                                                         object:nil];
   173     theSyncThread.name = @"pEp-sync-loop";
   174     self.syncThread = theSyncThread;
   175     [theSyncThread start];
   176 }
   177 
   178 - (void)shutdown
   179 {
   180     if (self.syncThread) {
   181         [self injectSyncEvent:nil];
   182         [self.conditionLockForJoiningSyncThread lockWhenCondition:YES];
   183         [self.conditionLockForJoiningSyncThread unlock];
   184     }
   185     self.conditionLockForJoiningSyncThread = nil;
   186 }
   187 
   188 // MARK: - Private
   189 
   190 + (PEPSync * _Nullable)instance
   191 {
   192     return s_pEpSync;
   193 }
   194 
   195 - (void)syncThreadLoop:(id)object
   196 {
   197     [self.conditionLockForJoiningSyncThread lock];
   198 
   199     PEPInternalSession *session = [PEPSessionProvider session];
   200 
   201     if (session) {
   202         register_sync_callbacks(session.session, nil, s_notifyHandshake,
   203                                 s_retrieve_next_sync_event);
   204         do_sync_protocol(session.session, nil);
   205         unregister_sync_callbacks(session.session);
   206     } else {
   207         // TODO: indicate error, maybe through `object`?
   208     }
   209 
   210     session = nil;
   211 
   212     [self.conditionLockForJoiningSyncThread unlockWithCondition:YES];
   213 }
   214 
   215 - (PEP_STATUS)messageToSend:(struct _message *)msg
   216 {
   217     if (self.sendMessageDelegate) {
   218         PEPMessage *theMessage = pEpMessageFromStruct(msg);
   219         return [self.sendMessageDelegate sendMessage:theMessage];
   220     } else {
   221         return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
   222     }
   223 }
   224 
   225 - (int)injectSyncEvent:(SYNC_EVENT)event
   226 {
   227     [self.queue enqueue:[NSValue valueWithBytes:&event objCType:@encode(SYNC_EVENT)]];
   228     return 0;
   229 }
   230 
   231 - (PEP_STATUS)notifyHandshake:(pEp_identity *)me
   232                       partner:(pEp_identity *)partner
   233                        signal:(sync_handshake_signal)signal
   234 {
   235     if (self.notifyHandshakeDelegate) {
   236         PEPIdentity *meIdentity = PEP_identityFromStruct(me);
   237         PEPIdentity *partnerIdentity = PEP_identityFromStruct(partner);
   238         return [self.notifyHandshakeDelegate notifyHandshake:NULL
   239                                                           me:meIdentity
   240                                                      partner:partnerIdentity
   241                                                       signal:signal];
   242     } else {
   243         return PEP_SYNC_NO_NOTIFY_CALLBACK;
   244     }
   245 }
   246 
   247 - (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold
   248 {
   249     NSValue *value = [self.queue timedDequeue:&threshold];
   250     if (value) {
   251         SYNC_EVENT event;
   252         [value getValue:&event];
   253         return event;
   254     } else {
   255         return new_sync_timeout_event();
   256     }
   257 }
   258 
   259 @end