pEpObjCAdapter/PEPSync.m
author Dirk Zimmermann <dz@pep.security>
Fri, 20 Sep 2019 17:00:26 +0200
branchIOSAD-132
changeset 1259 0cc3891ea776
parent 1152 c5d8810c470e
child 1252 e43abf52f198
permissions -rw-r--r--
IOSAD-132 Add PEPStatusCannotDeleteKey (PEP_CANNOT_DELETE_KEY).
dirk@681
     1
//
dirk@681
     2
//  PEPSync.m
dirk@681
     3
//  pEpObjCAdapter
dirk@681
     4
//
dirk@681
     5
//  Created by Dirk Zimmermann on 04.10.18.
dirk@681
     6
//  Copyright © 2018 p≡p. All rights reserved.
dirk@681
     7
//
dirk@681
     8
dz@995
     9
#import <os/log.h>
dz@995
    10
dirk@681
    11
#import "PEPSync.h"
dirk@681
    12
dz@944
    13
#import "pEpEngine.h"
dz@944
    14
dirk@732
    15
#import "PEPSendMessageDelegate.h"
dirk@704
    16
#import "PEPNotifyHandshakeDelegate.h"
dirk@688
    17
#import "PEPMessageUtil.h"
dz@902
    18
#import "PEPMessage.h"
dirk@700
    19
#import "PEPQueue.h"
dirk@725
    20
#import "PEPObjCAdapter.h"
dz@831
    21
#import "NSError+PEP+Internal.h"
dirk@751
    22
#import "PEPSessionProvider.h"
dirk@751
    23
#import "PEPInternalSession.h"
dirk@686
    24
dz@1152
    25
// MARK: - Internals
dz@1152
    26
dz@1152
    27
os_log_t s_logger;
dirk@693
    28
dirk@726
    29
typedef PEP_STATUS (* t_messageToSendCallback)(struct _message *msg);
dirk@726
    30
typedef int (* t_injectSyncCallback)(SYNC_EVENT ev, void *management);
dirk@726
    31
dirk@691
    32
@interface PEPSync ()
dirk@691
    33
dirk@699
    34
+ (PEPSync * _Nullable)instance;
dirk@691
    35
dirk@700
    36
@property (nonatomic, nonnull) PEPQueue *queue;
dirk@720
    37
@property (nonatomic, nullable) NSThread *syncThread;
dirk@736
    38
@property (nonatomic, nullable) NSConditionLock *conditionLockForJoiningSyncThread;
dirk@700
    39
dirk@726
    40
/**
dirk@726
    41
 @Return: The callback for message sending that should be used on every session init.
dirk@726
    42
 */
dirk@726
    43
+ (t_messageToSendCallback)messageToSendCallback;
dirk@726
    44
dirk@726
    45
/**
dirk@726
    46
 @Return: The callback for injectiong sync messages that should be used on every session init.
dirk@726
    47
 */
dirk@726
    48
+ (t_injectSyncCallback)injectSyncCallback;
dirk@726
    49
dirk@758
    50
- (PEP_STATUS)messageToSend:(struct _message *)msg;
dirk@758
    51
dirk@700
    52
- (int)injectSyncEvent:(SYNC_EVENT)event;
dirk@730
    53
dirk@730
    54
- (PEP_STATUS)notifyHandshake:(pEp_identity *)me
dirk@730
    55
                      partner:(pEp_identity *)partner
dirk@730
    56
                       signal:(sync_handshake_signal)signal;
dirk@730
    57
dirk@724
    58
- (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold;
dirk@692
    59
dirk@691
    60
@end
dirk@691
    61
dirk@728
    62
// MARK: - Callbacks called by the engine, used in session init
dirk@693
    63
dirk@740
    64
static PEP_STATUS s_messageToSendObjc(struct _message *msg)
dirk@682
    65
{
dirk@758
    66
    PEPSync *pEpSync = [PEPSync instance];
dirk@758
    67
dirk@758
    68
    if (pEpSync) {
dirk@758
    69
        return [pEpSync messageToSend:msg];
dirk@689
    70
    } else {
dirk@758
    71
        return PEP_SYNC_NO_NOTIFY_CALLBACK;
dirk@688
    72
    }
dirk@682
    73
}
dirk@682
    74
dirk@740
    75
static int s_inject_sync_event(SYNC_EVENT ev, void *management)
dirk@682
    76
{
dirk@700
    77
    PEPSync *pEpSync = [PEPSync instance];
dirk@700
    78
dirk@700
    79
    if (pEpSync) {
dirk@700
    80
        return [pEpSync injectSyncEvent:ev];
dirk@700
    81
    } else {
dirk@700
    82
        return 1;
dirk@700
    83
    }
dirk@682
    84
}
dirk@682
    85
dirk@728
    86
// MARK: - Callbacks called by the engine, used in register_sync_callbacks
dirk@728
    87
dirk@734
    88
static PEP_STATUS s_notifyHandshake(pEp_identity *me,
dirk@734
    89
                                    pEp_identity *partner,
dirk@734
    90
                                    sync_handshake_signal signal)
dirk@729
    91
{
dirk@758
    92
    PEPSync *pEpSync = [PEPSync instance];
dirk@758
    93
dirk@758
    94
    if (pEpSync) {
dirk@758
    95
        return [pEpSync notifyHandshake:me partner:partner signal:signal];
dirk@758
    96
    } else {
dirk@758
    97
        return PEP_SYNC_NO_NOTIFY_CALLBACK;
dirk@758
    98
    }
dirk@729
    99
}
dirk@729
   100
dirk@734
   101
static SYNC_EVENT s_retrieve_next_sync_event(void *management, unsigned threshold)
dirk@724
   102
{
dirk@733
   103
    PEPSync *sync = [PEPSync instance];
dirk@724
   104
    return [sync retrieveNextSyncEvent:threshold];
dirk@724
   105
}
dirk@724
   106
dirk@693
   107
// MARK: - Internal globals
dirk@693
   108
dirk@699
   109
static __weak PEPSync *s_pEpSync;
dirk@686
   110
dirk@720
   111
// MARK: - Public PEPSync class
dirk@693
   112
dirk@681
   113
@implementation PEPSync
dirk@681
   114
dirk@722
   115
+ (t_messageToSendCallback)messageToSendCallback
dirk@722
   116
{
dirk@740
   117
    return s_messageToSendObjc;
dirk@722
   118
}
dirk@722
   119
dirk@722
   120
+ (t_injectSyncCallback)injectSyncCallback
dirk@722
   121
{
dirk@740
   122
    return s_inject_sync_event;
dirk@722
   123
}
dirk@722
   124
dirk@725
   125
+ (PEP_SESSION)createSession:(NSError **)error
dirk@725
   126
{
dirk@725
   127
    PEP_SESSION session = NULL;
dirk@725
   128
dirk@725
   129
    PEP_STATUS status = init(&session,
dirk@725
   130
                             [PEPSync messageToSendCallback],
dirk@725
   131
                             [PEPSync injectSyncCallback]);
dirk@725
   132
dirk@725
   133
    if (status != PEP_STATUS_OK) {
dirk@725
   134
        if (error) {
dz@831
   135
            *error = [NSError errorWithPEPStatusInternal:status];
dz@1152
   136
            os_log(s_logger, "error creating session: %{public}@", *error);
dirk@725
   137
        }
dirk@725
   138
        return nil;
dirk@725
   139
    }
dirk@725
   140
dirk@725
   141
    return session;
dirk@725
   142
}
dirk@725
   143
dirk@732
   144
- (instancetype)initWithSendMessageDelegate:(id<PEPSendMessageDelegate>
andreas@1021
   145
                                             _Nullable)sendMessageDelegate
dirk@732
   146
                    notifyHandshakeDelegate:(id<PEPNotifyHandshakeDelegate>
andreas@1022
   147
                                             _Nullable)notifyHandshakeDelegate
dirk@695
   148
{
dirk@695
   149
    if (self = [super init]) {
dirk@732
   150
        _sendMessageDelegate = sendMessageDelegate;
dirk@699
   151
        _notifyHandshakeDelegate = notifyHandshakeDelegate;
dirk@700
   152
        _queue = [PEPQueue new];
dirk@699
   153
        s_pEpSync = self;
dirk@695
   154
    }
dirk@695
   155
    return self;
dirk@695
   156
}
dirk@695
   157
dirk@720
   158
- (void)startup
dirk@720
   159
{
andreas@1075
   160
    [self assureMainSessionExists];
dirk@757
   161
dirk@736
   162
    self.conditionLockForJoiningSyncThread = [[NSConditionLock alloc] initWithCondition:NO];
dirk@720
   163
    NSThread *theSyncThread = [[NSThread alloc] initWithTarget:self
dirk@720
   164
                                                      selector:@selector(syncThreadLoop:)
dirk@720
   165
                                                        object:nil];
dirk@756
   166
    theSyncThread.name = @"pEp-sync-loop";
dirk@720
   167
    self.syncThread = theSyncThread;
dirk@735
   168
    [theSyncThread start];
dirk@720
   169
}
dirk@720
   170
dirk@701
   171
- (void)shutdown
dirk@701
   172
{
dirk@736
   173
    if (self.syncThread) {
dirk@736
   174
        [self injectSyncEvent:nil];
dirk@736
   175
        [self.conditionLockForJoiningSyncThread lockWhenCondition:YES];
dirk@736
   176
        [self.conditionLockForJoiningSyncThread unlock];
dirk@736
   177
    }
dirk@736
   178
    self.conditionLockForJoiningSyncThread = nil;
dirk@701
   179
}
dirk@701
   180
dirk@720
   181
// MARK: - Private
dirk@720
   182
dz@1152
   183
+ (void)initialize
dz@1152
   184
{
dz@1152
   185
    s_logger = os_log_create("security.pEp.adapter", "PEPSync");
dz@1152
   186
}
dz@1152
   187
dirk@723
   188
+ (PEPSync * _Nullable)instance
dirk@723
   189
{
dirk@723
   190
    return s_pEpSync;
dirk@723
   191
}
dirk@723
   192
andreas@1075
   193
- (void)assureMainSessionExists
andreas@1075
   194
{
andreas@1075
   195
    PEPInternalSession *session __attribute__((unused)) = [PEPSessionProvider session];
andreas@1075
   196
}
andreas@1075
   197
dirk@736
   198
- (void)syncThreadLoop:(id)object
dirk@736
   199
{
dirk@736
   200
    [self.conditionLockForJoiningSyncThread lock];
dirk@736
   201
dz@1152
   202
    os_log(s_logger, "trying to start the sync loop");
dz@996
   203
dirk@751
   204
    PEPInternalSession *session = [PEPSessionProvider session];
dirk@727
   205
dirk@727
   206
    if (session) {
dz@995
   207
        PEP_STATUS status = register_sync_callbacks(session.session, nil, s_notifyHandshake,
dz@995
   208
                                                    s_retrieve_next_sync_event);
dz@995
   209
        if (status == PEP_STATUS_OK) {
dz@995
   210
            status = do_sync_protocol(session.session, nil);
dz@995
   211
            if (status != PEP_STATUS_OK) {
dz@1152
   212
                os_log_error(s_logger, "do_sync_protocol returned PEP_STATUS %d", status);
dz@1152
   213
                os_log(s_logger, "sync loop is NOT running");
dz@995
   214
            }
dz@995
   215
            unregister_sync_callbacks(session.session);
dz@995
   216
        } else {
dz@1152
   217
            os_log_error(s_logger, "register_sync_callbacks returned PEP_STATUS %d", status);
dz@1152
   218
            os_log(s_logger, "sync loop is NOT running");
dz@995
   219
        }
dirk@727
   220
    } else {
dz@1152
   221
        os_log_error(s_logger, "could not create session for starting the sync loop");
dirk@727
   222
    }
dirk@727
   223
dz@1152
   224
    os_log(s_logger, "sync loop finished");
dz@996
   225
dirk@751
   226
    session = nil;
dirk@736
   227
dirk@736
   228
    [self.conditionLockForJoiningSyncThread unlockWithCondition:YES];
dirk@720
   229
}
dirk@720
   230
dirk@758
   231
- (PEP_STATUS)messageToSend:(struct _message *)msg
dirk@758
   232
{
dirk@758
   233
    if (self.sendMessageDelegate) {
dirk@758
   234
        PEPMessage *theMessage = pEpMessageFromStruct(msg);
dz@988
   235
        return (PEP_STATUS) [self.sendMessageDelegate sendMessage:theMessage];
dirk@758
   236
    } else {
dirk@758
   237
        return PEP_SYNC_NO_MESSAGE_SEND_CALLBACK;
dirk@758
   238
    }
dirk@758
   239
}
dirk@758
   240
dirk@700
   241
- (int)injectSyncEvent:(SYNC_EVENT)event
dirk@700
   242
{
dirk@700
   243
    [self.queue enqueue:[NSValue valueWithBytes:&event objCType:@encode(SYNC_EVENT)]];
dirk@700
   244
    return 0;
dirk@700
   245
}
dirk@700
   246
dirk@730
   247
- (PEP_STATUS)notifyHandshake:(pEp_identity *)me
dirk@730
   248
                      partner:(pEp_identity *)partner
dirk@730
   249
                       signal:(sync_handshake_signal)signal
dirk@730
   250
{
dirk@730
   251
    if (self.notifyHandshakeDelegate) {
dirk@730
   252
        PEPIdentity *meIdentity = PEP_identityFromStruct(me);
dirk@730
   253
        PEPIdentity *partnerIdentity = PEP_identityFromStruct(partner);
dz@988
   254
        return (PEP_STATUS) [self.notifyHandshakeDelegate
dz@988
   255
                             notifyHandshake:NULL
dz@988
   256
                             me:meIdentity
dz@988
   257
                             partner:partnerIdentity
dz@988
   258
                             signal:(PEPSyncHandshakeSignal) signal];
dirk@730
   259
    } else {
dirk@730
   260
        return PEP_SYNC_NO_NOTIFY_CALLBACK;
dirk@730
   261
    }
dirk@730
   262
}
dirk@730
   263
dirk@724
   264
- (SYNC_EVENT)retrieveNextSyncEvent:(time_t)threshold
dirk@724
   265
{
dirk@724
   266
    NSValue *value = [self.queue timedDequeue:&threshold];
dirk@724
   267
    if (value) {
dirk@724
   268
        SYNC_EVENT event;
dirk@724
   269
        [value getValue:&event];
dirk@724
   270
        return event;
dirk@724
   271
    } else {
dirk@724
   272
        return new_sync_timeout_event();
dirk@724
   273
    }
dirk@724
   274
}
dirk@724
   275
dirk@681
   276
@end