adobkin / libcapn

A simple C Library for interact with the Apple Push Notification Service (APNs)
MIT License
100 stars 37 forks source link

apn_connect() block forever #9

Open hex2tan opened 9 years ago

hex2tan commented 9 years ago

Hi, this is my code, what just use the sample http://libcapn.org/doc/html/send_push_8c-example.html code, a little different is use the apn_payload_add_custom_property_string() in some codition. int32_t PushToApple(std::string& strIosToken, std::string& strMsg,int32_t nBadge,const char* pstrExt) { apn_payload_ctx_ref payload_ctx = NULL; apn_ctx_ref ctx = NULL; apn_error_ref error = NULL; const char cert_path = "apns-pro-cert.pem"; const char key_path = "apns-pro-key-noenc.pem"; const char push_message = strMsg.c_str(); const char token = strIosToken.c_str(); time_t time_now = 0; if(apn_init(&ctx, cert_path, key_path, NULL, &error) == APN_ERROR) { printf("%s: %d\n", apn_error_message(error), APN_ERR_CODE_WITHOUT_CLASS(apn_error_code(error))); apn_error_free(&error); return fail; } apn_set_mode(ctx, APN_MODE_SANDBOX, NULL); apn_add_token(ctx, token, NULL);

if(apn_payload_init(&payload_ctx, &error) == APN_ERROR)
{
    printf("%s: %d\n", apn_error_message(error), APN_ERR_CODE_WITHOUT_CLASS(apn_error_code(error)));
    apn_free(&ctx);
    apn_error_free(&error);
    return fail;
}

time(&time_now);
apn_payload_set_badge(payload_ctx, nBadge, NULL);
apn_payload_set_body(payload_ctx, push_message, NULL);
apn_payload_set_expiry(payload_ctx, time_now + 3600, NULL);
apn_payload_set_sound(payload_ctx, "default",  NULL);
apn_payload_add_custom_property_integer(payload_ctx, "int_property", 20, NULL);
if(NULL != pstrExt)
    apn_payload_add_custom_property_string(payload_ctx,"ext",pstrExt, NULL);

ctx->mode = APN_MODE_PRODUCTION;
if(apn_connect(ctx, &error) == APN_ERROR)
{
    printf("Could not connected to Apple Push Notification Servece: %s (%d)\n", apn_error_message(error), APN_ERR_CODE_WITHOUT_CLASS(apn_error_code(error)));
    apn_payload_free(&payload_ctx);
    apn_free(&ctx);
    apn_error_free(&error);
    return fail;
}

if(apn_send(ctx, payload_ctx, &error) == APN_ERROR)
{
    printf("Could not sent push: %s (%d)\n", apn_error_message(error),  APN_ERR_CODE_WITHOUT_CLASS(apn_error_code(error)));
    if(APN_ERR_CODE_WITHOUT_CLASS(apn_error_code(error)) == APN_ERR_TOKEN_INVALID)
    {
        printf("Invalid token: %s\n", apn_error_invalid_token(error));
    }
    apn_close(ctx);
    apn_payload_free(&payload_ctx);
    apn_free(&ctx);
    apn_error_free(&error);
    return fail;
}

apn_close(ctx);
apn_payload_free(&payload_ctx);
apn_free(&ctx);
return success;

} The code work fine most of time.But sometimes, it does not, the application was blocked by apn_connect() accidentally, once a day recently. Then I used the strace -p pid, just give a message blow: read(39, no more message. And with the gdb attach the application process id, the message blow: apn_gdb_bt_info it looks like block at read_nocancel(). So, after googling, I found the issues on stackoverflow: http://stackoverflow.com/questions/11835203/openssl-ssl-connect-blocks-forever-how-to-set-timeout and I view the libcapn source code, the __apn_connect() doesn't use the SSL_CTX_set_timeout() or SSL_SESSION_set_timeout(), of course it may have no effect just like that guy said. Following, I will try to add SSL_CTX_set_timeout() or SSL_SESSION_set_timeout() to the apn_connect() fuction and test it works or not.

I suggest give a fuction whic like apn_connect_timeout so that it can be setted the timeout. THX.

dungwinve commented 9 years ago

I met this problem too, how can you resolve this, can you share the method?

adobkin commented 9 years ago

I'll take care of the issue immediately as soon as possible. May be @hex2tan can check use SSL_CTX_set_timeout() before me

hex2tan commented 9 years ago

@dungwinve I don't have time to try SSL_CTX_set_timeout() or SSL_SESSION_set_timeout() yet. I have just used the SIGALRM signal to interrupt the block, and it work well for two weeks now.