2016-08-03 3 views
0

Ich arbeite an einem C-Programm, das die Bibliothek Libcapn (http://libcapn.org) verwendet, um eine Verbindung zu Push-Benachrichtigungsdienst von Apple herzustellen und Push-Benachrichtigungen zu senden.C Segmentation Fault (Libcapn APNS-Bibliothek)

Das Beispiel, das auf der Website gezeigt wird, funktioniert gut, ich kann damit Push-Benachrichtigungen an mein iPhone senden.

Jetzt werde ich dies in mein bestehendes Programm integrieren, um spezifischere Benachrichtigungen an mein iPhone zu senden, aber ich bekomme immer einen Segmentierungsfehler, wenn ich versuche, den Code in mehrere Funktionen aufzuteilen.

Beispiel: In dem gegebenen Code alles in der main Funktion geschieht:

int main() { 
    apn_payload_t *payload = NULL; 
    apn_ctx_t *ctx = NULL; 
    time_t time_now = 0; 
    char *invalid_token = NULL; 

    // ... 

    if(NULL == (ctx = apn_init())) { 
     printf("Unable to init context: %d\n", errno); 
     apn_library_free(); 
     return -1; 
    } 

    apn_set_pkcs12_file(ctx, "my-certificate.p12", "my4711passphrase"); 
    apn_set_mode(ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX 
    apn_set_behavior(ctx, APN_OPTION_RECONNECT); 
    apn_set_log_level(ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG); 
    apn_set_log_callback(ctx, __apn_logging); 
    apn_set_invalid_token_callback(ctx, __apn_invalid_token); 

    // ... 

} 

Obwohl es funktioniert es ist nicht genau das, was ich will. Ich möchte nicht alle Ressourcen zuweisen/freigeben, wenn ich eine einzige Benachrichtigung senden möchte. Daher möchte ich die Verbindung beim Start öffnen, den Modus auf "RECONNECT" setzen (damit sie sich automatisch wieder verbindet, nachdem die Verbindung geschlossen wurde) und einfach alle Ressourcen freigeben, wenn das Programm beendet wird.

Also wenn ich nur z. die Initialisierung der context zu einer neuen Funktion, bekomme ich einen Segmentierungsfehler. Hier ist, was ich getan habe:

int apn_ctx_init_wrapper(apn_ctx_t *ctx) { 
    if(NULL == (ctx = apn_init())) { 
     printf("Unable to init context: %d\n", errno); 
     apn_library_free(); 
     return -1; 
    } 

    apn_set_pkcs12_file(ctx, "my-certificate.p12", "my4711passphrase"); 
    apn_set_mode(ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX 
    apn_set_behavior(ctx, APN_OPTION_RECONNECT); 
    apn_set_log_level(ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG); 
    apn_set_log_callback(ctx, __apn_logging); 
    apn_set_invalid_token_callback(ctx, __apn_invalid_token); 

    return 0; 
} 

... und ich ersetzt den Code oben mit zu einem einzigen Funktionsaufruf wie apn_ctx_init_wrapper(ctx);. Es gibt nicht einmal 0 oder -1. Wenn die Funktion get aufgerufen wird, bekomme ich einen segfault. Warum? Bitte hilf mir!

+0

Da gibt es eine c-Routine namens 'connect()'. Während Sie Ihren Code nicht direkt gegen 'connect()' aufrufen oder kompilieren, wird 'apn_connect()' dies tun. Versuchen Sie, einen anderen Namen zu verwenden, der nicht mit einem vorhandenen Konflikt in Konflikt steht. Ich schlage 'apn_connect_wrapper()' vor, damit Sie und zukünftiger Maintainer sich daran erinnern, dass es nur ein Wrapper für die 'apn_connect()' ist. – alvits

+0

Sie haben Recht. Der Name wurde geändert und es funktioniert. Aber wenn ich einen anderen Code auslagere, bekomme ich immer noch einen segfault. Ich aktualisiere meine Frage. – beeef

+0

Diese 'ctx = apn_init()' setzt 'ctx' auf die von' apn_init() 'zurückgegebene Adresse. Das Problem ist, dass Sie die dynamisch zugewiesene Adresse verlieren, wenn 'apn_ctx_init_wrapper()' zum Aufrufer zurückkehrt.Denken Sie daran, dass Sie den Wert von 'ctx' aus' main() 'übergeben und in' apn_ctx_init_wrapper() 'Sie dachten, Sie ersetzen den Inhalt von' ctx', aber Sie sind nicht, weil Sie den Wert überschritten haben. Im späteren Teil Ihres Codes, wenn Sie 'ctx' referenzieren, enthält er immer noch den Anfangswert, den er vor dem Aufruf von' apn_ctx_init_wrapper() 'hatte. Ändern Sie den Wrapper, um 'apn_ctx_t ** ctx' zu akzeptieren. – alvits

Antwort

1

Dies ist ein klassischer Fall, bei dem ein Zeiger nach Wert übergeben wird und versucht wird, die lokale Kopie des Zeigers auf eine neue Position zu verweisen. Der ursprüngliche Zeiger zeigt auf den ursprünglichen Speicherort.

Ich werde Ihnen zwei Ansätze für diese Situation geben.

Sie können die Funktion so ändern, dass sie die Adresse des Zeigers akzeptiert.

int apn_ctx_init_wrapper(apn_ctx_t **ctx) { 
    if(NULL == (*ctx = apn_init())) { //Note that the pointer needs to be dereferenced 
     printf("Unable to init context: %d\n", errno); 
     apn_library_free(); 
     return -1; 
    } 

    apn_set_pkcs12_file(*ctx, "my-certificate.p12", "my4711passphrase"); 
    apn_set_mode(*ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX 
    apn_set_behavior(*ctx, APN_OPTION_RECONNECT); 
    apn_set_log_level(*ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG); 
    apn_set_log_callback(*ctx, __apn_logging); 
    apn_set_invalid_token_callback(*ctx, __apn_invalid_token); 

    return 0; 
} 

Und in Haupt können Sie es als if(apn_ctx_init_wrapper(&ctx) != -1) nennen.

Die zweite Methode besteht darin, den Kontext zurückzugeben, anstatt 0 oder -1 zurückzugeben.

apn_ctx_t *apn_ctx_init_wrapper() { 
    apn_ctx_t *ctx; 
    if(NULL == (ctx = apn_init())) { 
     printf("Unable to init context: %d\n", errno); 
     apn_library_free(); 
     return NULL; 
    } 

    apn_set_pkcs12_file(ctx, "my-certificate.p12", "my4711passphrase"); 
    apn_set_mode(ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX 
    apn_set_behavior(ctx, APN_OPTION_RECONNECT); 
    apn_set_log_level(ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG); 
apn_set_log_callback(ctx, __apn_logging); 
apn_set_invalid_token_callback(ctx, __apn_invalid_token); 

    return ctx; 
} 

Ein in Haupt können Sie es als if(NULL == (ctx = apn_ctx_init_wrapper())) nennen. Es ist nicht erforderlich, einen Kontext an die Funktion zu übergeben, da die Funktion den Kontext erstellt und initialisiert.

Ich bevorzuge die zweite Methode.

+0

Ich dachte, solange ich einen Zeiger übergeben, ist es in Ordnung. Hab nicht daran gedacht! Vielen Dank! – beeef