void cache_release(cache_t *cache, h2o_cache_ref_t *ref, h2o_cache_hashcode_t keyhash) { if (!keyhash) keyhash = h2o_cache_calchash(ref->key.base, ref->key.len); const size_t idx = get_index(cache->cache_num, keyhash); h2o_cache_release(cache->cache[idx], ref); }
void h2o_socket_ssl_handshake(h2o_socket_t *sock, SSL_CTX *ssl_ctx, const char *server_name, h2o_socket_cb handshake_cb) { sock->ssl = h2o_mem_alloc(sizeof(*sock->ssl)); memset(sock->ssl, 0, offsetof(struct st_h2o_socket_ssl_t, output.pool)); /* setup the buffers; sock->input should be empty, sock->ssl->input.encrypted should contain the initial input, if any */ h2o_buffer_init(&sock->ssl->input.encrypted, &h2o_socket_buffer_prototype); if (sock->input->size != 0) { h2o_buffer_t *tmp = sock->input; sock->input = sock->ssl->input.encrypted; sock->ssl->input.encrypted = tmp; } h2o_mem_init_pool(&sock->ssl->output.pool); create_ssl(sock, ssl_ctx); sock->ssl->handshake.cb = handshake_cb; if (server_name == NULL) { /* is server */ if (SSL_CTX_sess_get_get_cb(ssl_ctx) != NULL) sock->ssl->handshake.server.async_resumption.state = ASYNC_RESUMPTION_STATE_RECORD; if (sock->ssl->input.encrypted->size != 0) proceed_handshake(sock, 0); else h2o_socket_read_start(sock, proceed_handshake); } else { h2o_cache_t *session_cache = h2o_socket_ssl_get_session_cache(ssl_ctx); if (session_cache != NULL) { struct sockaddr_storage sa; int32_t port; if (h2o_socket_getpeername(sock, (struct sockaddr *)&sa) != 0 && (port = h2o_socket_getport((struct sockaddr *)&sa)) != -1) { /* session cache is available */ h2o_iovec_t session_cache_key; session_cache_key.base = h2o_mem_alloc(strlen(server_name) + sizeof(":" H2O_UINT16_LONGEST_STR)); session_cache_key.len = sprintf(session_cache_key.base, "%s:%" PRIu16, server_name, (uint16_t)port); sock->ssl->handshake.client.session_cache = session_cache; sock->ssl->handshake.client.session_cache_key = session_cache_key; sock->ssl->handshake.client.session_cache_key_hash = h2o_cache_calchash(session_cache_key.base, session_cache_key.len); /* fetch from session cache */ h2o_cache_ref_t *cacheref = h2o_cache_fetch(session_cache, h2o_now(h2o_socket_get_loop(sock)), sock->ssl->handshake.client.session_cache_key, sock->ssl->handshake.client.session_cache_key_hash); if (cacheref != NULL) { SSL_set_session(sock->ssl->ssl, (SSL_SESSION *)cacheref->value.base); h2o_cache_release(session_cache, cacheref); } } } sock->ssl->handshake.client.server_name = h2o_strdup(NULL, server_name, SIZE_MAX).base; SSL_set_tlsext_host_name(sock->ssl->ssl, sock->ssl->handshake.client.server_name); proceed_handshake(sock, 0); } }
h2o_cache_ref_t *cache_fetch(cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash) { if (!keyhash) keyhash = h2o_cache_calchash(key.base, key.len); const size_t idx = get_index(cache->cache_num, keyhash); pthread_mutex_t * const mutex = cache->cache_lock + idx; CHECK_ERROR(pthread_mutex_lock, mutex); h2o_cache_ref_t * const ret = h2o_cache_fetch(cache->cache[idx], now, key, keyhash); CHECK_ERROR(pthread_mutex_unlock, mutex); return ret; }
void h2o_cache_delete(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash) { h2o_cache_ref_t search_key; khiter_t iter; if (keyhash == 0) keyhash = h2o_cache_calchash(key.base, key.len); search_key.key = key; search_key.keyhash = keyhash; lock_cache(cache); purge(cache, now); if ((iter = kh_get(cache, cache->table, &search_key)) != kh_end(cache->table)) erase_ref(cache, iter, 0); unlock_cache(cache); }
h2o_cache_ref_t *h2o_cache_fetch(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash) { h2o_cache_ref_t search_key, *ref; khiter_t iter; int64_t timeleft; if (keyhash == 0) keyhash = h2o_cache_calchash(key.base, key.len); search_key.key = key; search_key.keyhash = keyhash; lock_cache(cache); purge(cache, now); if ((iter = kh_get(cache, cache->table, &search_key)) == kh_end(cache->table)) goto NotFound; /* found */ ref = kh_key(cache->table, iter); timeleft = get_timeleft(cache, ref, now); if (timeleft < 0) goto NotFound; if ((cache->flags & H2O_CACHE_FLAG_EARLY_UPDATE) != 0 && timeleft < 10 && !ref->_requested_early_update) { ref->_requested_early_update = 1; goto NotFound; } /* move the entry to the top of LRU */ h2o_linklist_unlink(&ref->_lru_link); h2o_linklist_insert(&cache->lru, &ref->_lru_link); __sync_fetch_and_add(&ref->_refcnt, 1); /* unlock and return the found entry */ unlock_cache(cache); return ref; NotFound: unlock_cache(cache); return NULL; }
int h2o_cache_set(h2o_cache_t *cache, uint64_t now, h2o_iovec_t key, h2o_cache_hashcode_t keyhash, h2o_iovec_t value) { h2o_cache_ref_t *newref; khiter_t iter; int existed; if (keyhash == 0) keyhash = h2o_cache_calchash(key.base, key.len); /* create newref */ newref = h2o_mem_alloc(sizeof(*newref)); *newref = (h2o_cache_ref_t){h2o_strdup(NULL, key.base, key.len), keyhash, now, value, 0, {}, {}, 1}; lock_cache(cache); /* set or replace the named value */ iter = kh_get(cache, cache->table, newref); if (iter != kh_end(cache->table)) { erase_ref(cache, iter, 1); kh_key(cache->table, iter) = newref; existed = 1; } else { int unused; kh_put(cache, cache->table, newref, &unused); existed = 0; } h2o_linklist_insert(&cache->lru, &newref->_lru_link); h2o_linklist_insert(&cache->age, &newref->_age_link); cache->size += newref->value.len; purge(cache, now); unlock_cache(cache); return existed; }