Author: rhuijben Date: Sun Nov 29 11:09:44 2015 New Revision: 1717031 URL: http://svn.apache.org/viewvc?rev=1717031&view=rev Log: With the config store available we now have a location to store ssl session state for resumption keyed by host+portnumber. Use this to optimize creating additional ssl sessions (and in case of http/1.1 resetting connections), within a single serf context.
* buckets/ssl_buckets.c (ssl_handshake): Check the config to see if we have a cached session. * config_store.c (ssl_session_data): New struct. (SERF_CONFIG__SSL_SESSION): New config value. (serf__config_store_set_ssl_session, serf__config_store_get_ssl_session): New function. * serf_private.h (serf__config_store_set_ssl_session, serf__config_store_get_ssl_session): New function. Modified: serf/trunk/buckets/ssl_buckets.c serf/trunk/config_store.c serf/trunk/serf_private.h Modified: serf/trunk/buckets/ssl_buckets.c URL: http://svn.apache.org/viewvc/serf/trunk/buckets/ssl_buckets.c?rev=1717031&r1=1717030&r2=1717031&view=diff ============================================================================== --- serf/trunk/buckets/ssl_buckets.c (original) +++ serf/trunk/buckets/ssl_buckets.c Sun Nov 29 11:09:44 2015 @@ -917,6 +917,19 @@ static apr_status_t ssl_handshake(serf_s int do_want_read) { int ssl_result; + const unsigned char *data; + apr_size_t len; + + /* If we have a cached session, use it to allow speeding up the handshake */ + if (ctx->config + && !serf__config_store_get_ssl_session(ctx->config, &data, &len)) { + + SSL_SESSION *sess; + + sess = d2i_SSL_SESSION(NULL, &data, (long)len); + + SSL_set_session(ctx->ssl, sess); + } ctx->crypt_status = APR_SUCCESS; /* Clear before calling SSL */ ssl_result = SSL_do_handshake(ctx->ssl); @@ -1547,6 +1560,32 @@ void serf_ssl_server_cert_chain_callback context->server_cert_userdata = data; } +static int ssl_new_session(SSL *ssl, SSL_SESSION *session) +{ + serf_ssl_context_t *ctx = SSL_get_app_data(ssl); + void *mem; + unsigned char *der_data; + apr_size_t der_len; + + if (!ctx->config) + return 0; + + der_len = i2d_SSL_SESSION(session, NULL); + + mem = serf_bucket_mem_alloc(ctx->allocator, der_len); + der_data = mem; + if (der_len == i2d_SSL_SESSION(session, &der_data)) { + /* der_data was modified by i2d_SSL_SESSION(), so + we store the original pointer */ + (void)serf__config_store_set_ssl_session(ctx->config, + mem, der_len); + } + + serf_bucket_mem_free(ctx->allocator, mem); + + return 0; +} + static serf_ssl_context_t *ssl_init_context(serf_bucket_alloc_t *allocator) { serf_ssl_context_t *ssl_ctx; @@ -1596,6 +1635,10 @@ static serf_ssl_context_t *ssl_init_cont SSL_set_bio(ssl_ctx->ssl, ssl_ctx->bio, ssl_ctx->bio); + /* Enable SSL callback to store the SSL session state to allow + optimized resumption later. */ + SSL_CTX_sess_set_new_cb(ssl_ctx->ctx, ssl_new_session); + SSL_set_connect_state(ssl_ctx->ssl); SSL_set_app_data(ssl_ctx->ssl, ssl_ctx); Modified: serf/trunk/config_store.c URL: http://svn.apache.org/viewvc/serf/trunk/config_store.c?rev=1717031&r1=1717030&r2=1717031&view=diff ============================================================================== --- serf/trunk/config_store.c (original) +++ serf/trunk/config_store.c Sun Nov 29 11:09:44 2015 @@ -475,3 +475,52 @@ apr_status_t serf_config_remove_value(se { return serf_config_set_object(config, key, NULL); } + +struct ssl_session_data +{ + unsigned char *session; + apr_size_t session_len; +}; + +#define SERF_CONFIG__SSL_SESSION (SERF_CONFIG_PER_HOST | 0xF00001) + +apr_status_t +serf__config_store_set_ssl_session(serf_config_t *config, + const unsigned char *session, + apr_size_t session_len) +{ + struct ssl_session_data *ssld = serf_bucket_mem_alloc(config->allocator, + sizeof(*ssld) + + session_len); + + ssld->session = ((unsigned char *)ssld) + sizeof(*ssld); + ssld->session_len = session_len; + + memcpy(ssld->session, session, session_len); + + return config_set_object(config, SERF_CONFIG__SSL_SESSION, ssld, + serf_bucket_mem_free); +} + +apr_status_t +serf__config_store_get_ssl_session(serf_config_t *config, + const unsigned char **session, + apr_size_t *session_len) +{ + const struct ssl_session_data *ssld; + apr_status_t status; + void *value; + + status = serf_config_get_object(config, SERF_CONFIG__SSL_SESSION, &value); + + if (status) + return status; + else if (!value) + return APR_ENOENT; + + ssld = value; + + *session = ssld->session; + *session_len = ssld->session_len; + return APR_SUCCESS; +} Modified: serf/trunk/serf_private.h URL: http://svn.apache.org/viewvc/serf/trunk/serf_private.h?rev=1717031&r1=1717030&r2=1717031&view=diff ============================================================================== --- serf/trunk/serf_private.h (original) +++ serf/trunk/serf_private.h Sun Nov 29 11:09:44 2015 @@ -352,6 +352,16 @@ apr_status_t serf__config_store_create_l apr_status_t serf__config_store_create_ctx_config(serf_context_t *ctx, serf_config_t **config); +/* Stores session data for a host in the session cache*/ +apr_status_t serf__config_store_set_ssl_session(serf_config_t *config, + const unsigned char *session, + apr_size_t session_len); + +/* Tries to get session data for a host from the session cache */ +apr_status_t serf__config_store_get_ssl_session(serf_config_t *config, + const unsigned char **session, + apr_size_t *session_len); + /* Cleans up all connection specific configuration values */ apr_status_t