NOEXPORT int decrypt_session_ticket_cb(SSL *ssl, SSL_SESSION *sess,
        const unsigned char *keyname, size_t keyname_len,
        SSL_TICKET_STATUS status, void *arg) {
    TICKET_DATA *ticket_data;
    size_t ticket_len;

    (void)ssl; /* squash the unused parameter warning */
    (void)keyname; /* squash the unused parameter warning */
    (void)keyname_len; /* squash the unused parameter warning */
    (void)arg; /* squash the unused parameter warning */

    s_log(LOG_DEBUG, "Decrypt session ticket callback");

    switch(status) {
    case SSL_TICKET_EMPTY:
    case SSL_TICKET_NO_DECRYPT:
        return SSL_TICKET_RETURN_IGNORE_RENEW;
    case SSL_TICKET_SUCCESS:
    case SSL_TICKET_SUCCESS_RENEW:
        break;
    default:
        return SSL_TICKET_RETURN_ABORT;
    }

    if(!SSL_SESSION_get0_ticket_appdata(sess,
            (void **)&ticket_data, &ticket_len)) {
        s_log(LOG_WARNING, "Failed to get ticket application data");
        return SSL_TICKET_RETURN_IGNORE_RENEW;
    }
    if(!ticket_data) {
        s_log(LOG_WARNING, "Invalid ticket application data value");
        return SSL_TICKET_RETURN_IGNORE_RENEW;
    }
    if(ticket_len != sizeof(TICKET_DATA)) {
        s_log(LOG_WARNING, "Invalid ticket application data length");
        return SSL_TICKET_RETURN_IGNORE_RENEW;
    }

    s_log(LOG_INFO, "Decrypted ticket for an authenticated session: %s",
        ticket_data->session_authenticated ? "yes" : "no");
    SSL_SESSION_set_ex_data(sess, index_session_authenticated,
        ticket_data->session_authenticated);

#if 0
    if(ticket_data->addr.sa.sa_family) {
        char *addr_txt;
        SOCKADDR_UNION *old_addr;

        addr_txt=s_ntop(&ticket_data->addr, addr_len(&ticket_data->addr));
        s_log(LOG_INFO, "Decrypted ticket persistence address: %s", addr_txt);
        str_free(addr_txt);
        CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_ADDR]);
        old_addr=SSL_SESSION_get_ex_data(sess, index_session_connect_address);
        if(SSL_SESSION_set_ex_data(sess, index_session_connect_address, &ticket_data->addr)) {
            CRYPTO_THREAD_unlock(stunnel_locks[LOCK_ADDR]);
            str_free(old_addr); /* NULL pointers are ignored */
        } else { /* failed to store ticket_data->addr */
            CRYPTO_THREAD_unlock(stunnel_locks[LOCK_ADDR]);
            sslerror("SSL_SESSION_set_ex_data");
        }
    } else {
        s_log(LOG_INFO, "Decrypted ticket did not include a persistence address");
    }
#endif

    switch(status) {
    case SSL_TICKET_SUCCESS:
        return SSL_TICKET_RETURN_USE;
    case SSL_TICKET_SUCCESS_RENEW:
        return SSL_TICKET_RETURN_USE_RENEW;
    }
    return SSL_TICKET_RETURN_ABORT; /* it should never get executed */
}
NOEXPORT int decrypt_session_ticket_cb(SSL *ssl, SSL_SESSION *sess,
        const unsigned char *keyname, size_t keyname_len,
        SSL_TICKET_STATUS status, void *arg) {
    TICKET_DATA *ticket_data;
    size_t ticket_len;

    (void)ssl;  
    (void)keyname;  
    (void)keyname_len;  
    (void)arg;  

    s_log(LOG_DEBUG, "Decrypt session ticket callback");

    switch(status) {
    case SSL_TICKET_EMPTY:
    case SSL_TICKET_NO_DECRYPT:
        return SSL_TICKET_RETURN_IGNORE_RENEW;
    case SSL_TICKET_SUCCESS:
    case SSL_TICKET_SUCCESS_RENEW:
        break;
    default:
        return SSL_TICKET_RETURN_ABORT;
    }

    if(!SSL_SESSION_get0_ticket_appdata(sess,
            (void **)&ticket_data, &ticket_len)) {
        s_log(LOG_WARNING, "Failed to get ticket application data");
        return SSL_TICKET_RETURN_IGNORE_RENEW;
    }
    if(!ticket_data) {
        s_log(LOG_WARNING, "Invalid ticket application data value");
        return SSL_TICKET_RETURN_IGNORE_RENEW;
    }
    if(ticket_len != sizeof(TICKET_DATA)) {
        s_log(LOG_WARNING, "Invalid ticket application data length");
        return SSL_TICKET_RETURN_IGNORE_RENEW;
    }

    s_log(LOG_INFO, "Decrypted ticket for an authenticated session: %s",
        ticket_data->session_authenticated ? "yes" : "no");
    SSL_SESSION_set_ex_data(sess, index_session_authenticated,
        ticket_data->session_authenticated);

#if 0
    if(ticket_data->addr.sa.sa_family) {
        char *addr_txt;
        SOCKADDR_UNION *old_addr;

        addr_txt=s_ntop(&ticket_data->addr, addr_len(&ticket_data->addr));
        s_log(LOG_INFO, "Decrypted ticket persistence address: %s", addr_txt);
        str_free(addr_txt);
        CRYPTO_THREAD_write_lock(stunnel_locks[LOCK_ADDR]);
        old_addr=SSL_SESSION_get_ex_data(sess, index_session_connect_address);
        if(SSL_SESSION_set_ex_data(sess, index_session_connect_address, &ticket_data->addr)) {
            CRYPTO_THREAD_unlock(stunnel_locks[LOCK_ADDR]);
            str_free(old_addr);  
        } else {  
            CRYPTO_THREAD_unlock(stunnel_locks[LOCK_ADDR]);
            sslerror("SSL_SESSION_set_ex_data");
        }
    } else {
        s_log(LOG_INFO, "Decrypted ticket did not include a persistence address");
    }
#endif

    switch(status) {
    case SSL_TICKET_SUCCESS:
        return SSL_TICKET_RETURN_USE;
    case SSL_TICKET_SUCCESS_RENEW:
        return SSL_TICKET_RETURN_USE_RENEW;
    }
    return SSL_TICKET_RETURN_ABORT;  
}