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