pEpObjCAdapter/PEPObjCAdapter.m
author Dirk Zimmermann <dirk@pep-project.org>
Wed, 17 May 2017 09:27:57 +0200
changeset 187 1f630a05e444
child 191 c0872370f8fa
permissions -rw-r--r--
IOSAD-15 more renames
     1 //
     2 //  pEpiOSAdapter.m
     3 //  pEpiOSAdapter
     4 //
     5 //  Created by Volker Birk on 28.04.15.
     6 //  Copyright (c) 2015 p≡p. All rights reserved.
     7 //
     8 
     9 @import Foundation;
    10 
    11 #import "PEPObjCAdapter.h"
    12 #import "PEPObjCAdapter+Internal.h"
    13 #import "PEPMessage.h"
    14 #include "keymanagement.h"
    15 
    16 ///////////////////////////////////////////////////////////////////////////////
    17 //  Keyserver and Identity lookup - C part
    18 
    19 
    20 int examine_identity(pEp_identity *ident, void *management)
    21 {
    22     //PEPQueue *q = (__bridge PEPQueue *)management;
    23     PEPQueue *q = [PEPObjCAdapter getLookupQueue];
    24     
    25     NSDictionary *identity = PEP_identityDictFromStruct(ident);
    26     
    27     [q enqueue:identity];
    28     return 0;
    29 }
    30 
    31 static pEp_identity *retrieve_next_identity(void *management)
    32 {
    33     //PEPQueue *q = (__bridge PEPQueue *)management;
    34     PEPQueue *q = [PEPObjCAdapter getLookupQueue];
    35     
    36     // Dequeue is a blocking operation
    37     // that returns nil when queue is killed
    38     NSDictionary *ident = [q dequeue];
    39     
    40     if (ident)
    41         return PEP_identityDictToStruct(ident);
    42     else
    43         return NULL;
    44 }
    45 
    46 ///////////////////////////////////////////////////////////////////////////////
    47 // Sync - C part
    48 
    49 // Called by sync thread only
    50 PEP_STATUS notify_handshake(void *unused_object, pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal)
    51 {
    52     id <PEPSyncDelegate> syncDelegate = [PEPObjCAdapter getSyncDelegate];
    53     if ( syncDelegate )
    54         return [syncDelegate
    55                 notifyHandshakeWithSignal:signal
    56                 me:PEP_identityDictFromStruct(me)
    57                 partner:PEP_identityDictFromStruct(partner)];
    58     else
    59         return PEP_SYNC_NO_NOTIFY_CALLBACK;
    60 }
    61 
    62 // Called by sync thread only
    63 PEP_STATUS message_to_send(void *unused_object, message *msg)
    64 {
    65     id <PEPSyncDelegate> syncDelegate = [PEPObjCAdapter getSyncDelegate];
    66     if ( syncDelegate )
    67         return [syncDelegate sendMessage:PEP_messageDictFromStruct(msg)];
    68     else
    69         return PEP_SEND_FUNCTION_NOT_REGISTERED;
    70 }
    71 
    72 // called indirectly by decrypt message - any thread/session
    73 int inject_sync_msg(void *msg, void *unused_management)
    74 {
    75     PEPQueue *q = [PEPObjCAdapter getSyncQueue];
    76     
    77     [q enqueue:[NSValue valueWithPointer:msg]];
    78     
    79     return 0;
    80 }
    81 
    82 // Called by sync thread only
    83 void *retrieve_next_sync_msg(void *unused_mamagement, time_t *timeout)
    84 {
    85     PEPQueue *q = [PEPObjCAdapter getSyncQueue];
    86     
    87     return (void*)[[q dequeue] pointerValue];
    88 }
    89 
    90 
    91 ///////////////////////////////////////////////////////////////////////////////
    92 // DB and paths
    93 
    94 const char* _Nullable SystemDB = NULL;
    95 NSURL *s_homeURL;
    96 
    97 @implementation PEPObjCAdapter
    98 
    99 + (void)initialize
   100 {
   101     s_homeURL = [self createApplicationDirectory];
   102 }
   103 
   104 + (NSURL *)homeURL
   105 {
   106     return s_homeURL;
   107 }
   108 
   109 + (NSURL *)createApplicationDirectory
   110 {
   111     NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
   112     if (!bundleID) {
   113         // This can happen in unit tests
   114         bundleID = @"test";
   115     }
   116     NSFileManager *fm = [NSFileManager defaultManager];
   117     NSURL *dirPath = nil;
   118 
   119     // Find the application support directory in the home directory.
   120     NSArray *appSupportDir = [fm URLsForDirectory:NSApplicationSupportDirectory
   121                                         inDomains:NSUserDomainMask];
   122     if ([appSupportDir count] > 0)
   123     {
   124         // Append the bundle ID to the URL for the
   125         // Application Support directory.
   126         // Mainly needed for OS X, but doesn't do any harm on iOS
   127         dirPath = [[appSupportDir objectAtIndex:0] URLByAppendingPathComponent:bundleID];
   128 
   129         // If the directory does not exist, this method creates it.
   130         // This method is only available in OS X v10.7 and iOS 5.0 or later.
   131         NSError *theError = nil;
   132         if (![fm createDirectoryAtURL:dirPath withIntermediateDirectories:YES
   133                            attributes:nil error:&theError])
   134         {
   135             // Handle the error.
   136             return nil;
   137         }
   138     }
   139 
   140     return dirPath;
   141 }
   142 
   143 + (NSURL *)createAndSetHomeDirectory
   144 {
   145     // create and set home directory
   146     setenv("HOME", [[s_homeURL path] cStringUsingEncoding:NSUTF8StringEncoding], 1);
   147 
   148     // create and set temp directory
   149     NSURL *tmpDirUrl = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
   150     setenv("TEMP", [[tmpDirUrl path] cStringUsingEncoding:NSUTF8StringEncoding], 1);
   151 
   152     return s_homeURL;
   153 }
   154 
   155 + (NSString *) getBundlePathFor: (NSString *) filename
   156 {
   157     return nil;
   158 }
   159 
   160 + (NSString *) copyAssetIntoDocumentsDirectory:(NSBundle *)rootBundle
   161                                                           :(NSString *)bundleName
   162                                                           :(NSString *)fileName{
   163 
   164     NSURL *homeUrl = [PEPObjCAdapter createAndSetHomeDirectory];
   165     NSString *documentsDirectory = [homeUrl path];
   166     
   167     if(!(documentsDirectory && bundleName && fileName))
   168         return nil;
   169     
   170     // Check if the database file exists in the documents directory.
   171     NSString *destinationPath = [documentsDirectory stringByAppendingPathComponent:fileName];
   172     if (![[NSFileManager defaultManager] fileExistsAtPath:destinationPath]) {
   173         // The file does not exist in the documents directory, so copy it from bundle now.
   174         NSBundle *bundleObj = [NSBundle bundleWithPath:
   175                                [[rootBundle resourcePath]
   176                                 stringByAppendingPathComponent: bundleName]];
   177         
   178         if (!bundleObj)
   179             return nil;
   180         
   181         NSString *sourcePath =[[bundleObj resourcePath] stringByAppendingPathComponent: fileName];
   182         
   183         NSError *error;
   184         [[NSFileManager defaultManager]
   185          copyItemAtPath:sourcePath toPath:destinationPath error:&error];
   186         
   187         // Check if any error occurred during copying and display it.
   188         if (error != nil) {
   189             NSLog(@"%@", [error localizedDescription]);
   190             return nil;
   191         }
   192     }
   193     NSLog(@"Asset %@ copied into %@", fileName, destinationPath);
   194     return destinationPath;
   195 }
   196 
   197 + (void)setupTrustWordsDB:(NSBundle *)rootBundle{
   198     NSString *systemDBPath = [PEPObjCAdapter copyAssetIntoDocumentsDirectory:rootBundle
   199                                                                            :@"pEpTrustWords.bundle"
   200                                                                            :@"system.db"];
   201     if (SystemDB) {
   202         free((void *) SystemDB);
   203     }
   204     SystemDB = strdup(systemDBPath.UTF8String);
   205 }
   206 
   207 + (void)setupTrustWordsDB
   208 {
   209     [PEPObjCAdapter setupTrustWordsDB:[NSBundle mainBundle]];
   210 }
   211 
   212 static NSMutableArray* boundSessions = nil;
   213 
   214 + (NSMutableArray*)boundSessions
   215 {
   216     static dispatch_once_t once;
   217     dispatch_once(&once, ^{
   218         boundSessions =  [[NSMutableArray alloc] init];
   219     });
   220     return boundSessions;
   221 }
   222 
   223 ///////////////////////////////////////////////////////////////////////////////
   224 //  Keyserver and Identity lookup - ObjC part
   225 
   226 static PEPQueue *lookupQueue = nil;
   227 static NSThread *lookupThread = nil;
   228 static NSConditionLock *lookupThreadJoinCond = nil;
   229 
   230 + (void)lookupThreadRoutine:(id)object
   231 {
   232     [lookupThreadJoinCond lock];
   233 
   234     // FIXME: do_KeyManagement asserts if management is null.
   235     do_keymanagement(retrieve_next_identity, "NOTNULL" /* (__bridge void *)queue */);
   236     
   237     // Set and signal join()
   238     [lookupThreadJoinCond unlockWithCondition:YES];
   239 }
   240 
   241 + (void)startKeyserverLookup
   242 {
   243     if (!lookupQueue)
   244     {
   245         lookupQueue = [[PEPQueue alloc]init];
   246         
   247         // There is no join() call on NSThreads.
   248         lookupThreadJoinCond = [[NSConditionLock alloc] initWithCondition:NO];
   249         
   250         lookupThread = [[NSThread alloc] initWithTarget:self selector:@selector(lookupThreadRoutine:) object:nil];
   251         [lookupThread start];
   252     }
   253 }
   254 
   255 + (void)stopKeyserverLookup
   256 {
   257     
   258     if (lookupQueue)
   259     {
   260         // Flush queue and kick the consumer
   261         [lookupQueue kill];
   262         
   263         // Thread then bailout. Wait for that.
   264         [lookupThreadJoinCond lockWhenCondition:YES];
   265         [lookupThreadJoinCond unlock];
   266         
   267         lookupThread = nil;
   268         lookupQueue = nil;
   269         lookupThreadJoinCond = nil;
   270     }
   271 }
   272 
   273 + (void)registerExamineFunction:(PEP_SESSION)session
   274 {
   275     register_examine_function(session, examine_identity, NULL /* (__bridge void *)queue */);
   276 }
   277 
   278 + (PEPQueue*)getLookupQueue
   279 {
   280     return lookupQueue;
   281 }
   282 
   283 ///////////////////////////////////////////////////////////////////////////////
   284 // Sync - ObjC part
   285 
   286 static PEPQueue *syncQueue = nil;
   287 static NSThread *syncThread = nil;
   288 static NSConditionLock *syncThreadJoinCond = nil;
   289 static PEP_SESSION sync_session = NULL;
   290 static id <PEPSyncDelegate> syncDelegate = nil;
   291 
   292 
   293 + (void)syncThreadRoutine:(id)object
   294 {
   295     [syncThreadJoinCond lock];
   296     
   297     PEP_STATUS status = init(&sync_session);
   298     if (status != PEP_STATUS_OK) {
   299         return;
   300     }
   301     
   302     register_sync_callbacks(sync_session,
   303                              /* "management" : queuing (unused) */
   304                             "NOTNULL",
   305                             message_to_send,
   306                             notify_handshake,
   307                             inject_sync_msg,
   308                             retrieve_next_sync_msg);
   309 
   310     status = do_sync_protocol(sync_session,
   311                               /* "object" : notifying, sending (unused) */
   312                               "NOTNULL");
   313     
   314     // TODO : detach all attached sessions
   315     
   316     release(sync_session);
   317     
   318     [syncThreadJoinCond unlockWithCondition:YES];
   319 }
   320 
   321 + (void)attachSyncSession:(PEP_SESSION)session
   322 {
   323     if(sync_session)
   324         attach_sync_session(session, sync_session);
   325 }
   326 
   327 + (void)detachSyncSession:(PEP_SESSION)session
   328 {
   329     detach_sync_session(session);
   330 }
   331 
   332 + (void)startSync:(id <PEPSyncDelegate>)delegate;
   333 {
   334     syncDelegate = delegate;
   335     
   336     if (!syncQueue)
   337     {
   338         syncQueue = [[PEPQueue alloc]init];
   339         
   340         syncThreadJoinCond = [[NSConditionLock alloc] initWithCondition:NO];
   341         
   342         syncThread = [[NSThread alloc]
   343                       initWithTarget:self
   344                       selector:@selector(syncThreadRoutine:)
   345                       object:nil];
   346 
   347         [syncThread start];
   348     }
   349 
   350     NSMutableArray* sessionList = [PEPObjCAdapter boundSessions];
   351     PEPSession* session;
   352     @synchronized (sessionList) {
   353         for (session in sessionList) {
   354             [PEPObjCAdapter attachSyncSession:[session session]];
   355         }
   356     }
   357 }
   358 
   359 + (void)stopSync
   360 {
   361     NSMutableArray* sessionList = [PEPObjCAdapter boundSessions];
   362     PEPSession* session;
   363     @synchronized (sessionList) {
   364         for (session in sessionList) {
   365             [PEPObjCAdapter detachSyncSession:[session session]];
   366         }
   367     }
   368     
   369     syncDelegate = nil;
   370     
   371     if (syncQueue)
   372     {
   373         // FIXME : memory leak ! unallocate sync message waiting in the queue
   374         
   375         [syncQueue kill];
   376         
   377         [syncThreadJoinCond lockWhenCondition:YES];
   378         [syncThreadJoinCond unlock];
   379         
   380         syncThread = nil;
   381         syncQueue = nil;
   382         syncThreadJoinCond = nil;
   383     }
   384 }
   385 
   386 + (PEPQueue*)getSyncQueue
   387 {
   388     return syncQueue;
   389 }
   390 
   391 + (id <PEPSyncDelegate>)getSyncDelegate
   392 {
   393     return syncDelegate;
   394 }
   395 
   396 + (void)bindSession:(PEPSession*)session
   397 {
   398     NSMutableArray* sessionList = [PEPObjCAdapter boundSessions];
   399     @synchronized (sessionList) {
   400         [sessionList addObject:session];
   401     }
   402 
   403     [PEPObjCAdapter registerExamineFunction:[session session]];
   404     [PEPObjCAdapter attachSyncSession:[session session]];
   405 }
   406 
   407 + (void)unbindSession:(PEPSession*)session
   408 {
   409     [PEPObjCAdapter detachSyncSession:[session session]];
   410     
   411     NSMutableArray* sessionList = [PEPObjCAdapter boundSessions];
   412     @synchronized (sessionList) {
   413         [sessionList removeObject:session];
   414     }
   415 
   416 }
   417 
   418 
   419 
   420 @end