int h2o_socketpool_return(h2o_socketpool_t *pool, h2o_socket_t *sock) { struct pool_entry_t *entry; /* reset the on_close callback */ assert(sock->on_close.data == pool); sock->on_close.cb = NULL; sock->on_close.data = NULL; entry = h2o_mem_alloc(sizeof(*entry)); if (h2o_socket_export(sock, &entry->sockinfo) != 0) { free(entry); __sync_sub_and_fetch(&pool->_shared.count, 1); return -1; } memset(&entry->link, 0, sizeof(entry->link)); entry->added_at = h2o_now(h2o_socket_get_loop(sock)); pthread_mutex_lock(&pool->_shared.mutex); destroy_expired(pool); h2o_linklist_insert(&pool->_shared.sockets, &entry->link); pthread_mutex_unlock(&pool->_shared.mutex); return 0; }
static void on_timeout(h2o_timeout_entry_t *timeout_entry) { /* FIXME decrease the frequency of this function being called; the expiration * check can be (should be) performed in the `connect` fuction as well */ h2o_socketpool_t *pool = H2O_STRUCT_FROM_MEMBER(h2o_socketpool_t, _interval_cb.entry, timeout_entry); if (pthread_mutex_trylock(&pool->_shared.mutex) == 0) { destroy_expired(pool); pthread_mutex_unlock(&pool->_shared.mutex); } h2o_timeout_link(pool->_interval_cb.loop, &pool->_interval_cb.timeout, &pool->_interval_cb.entry); }
void h2o_socketpool_connect(h2o_socketpool_connect_request_t **_req, h2o_socketpool_t *pool, h2o_loop_t *loop, h2o_multithread_receiver_t *getaddr_receiver, h2o_socketpool_connect_cb cb, void *data) { struct pool_entry_t *entry = NULL; if (_req != NULL) *_req = NULL; /* fetch an entry */ pthread_mutex_lock(&pool->_shared.mutex); destroy_expired(pool); if (!h2o_linklist_is_empty(&pool->_shared.sockets)) { entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, link, pool->_shared.sockets.next); h2o_linklist_unlink(&entry->link); }
void h2o_socketpool_connect(h2o_socketpool_connect_request_t **_req, h2o_socketpool_t *pool, h2o_loop_t *loop, h2o_multithread_receiver_t *getaddr_receiver, h2o_socketpool_connect_cb cb, void *data) { struct pool_entry_t *entry = NULL; if (_req != NULL) *_req = NULL; /* fetch an entry and return it */ pthread_mutex_lock(&pool->_shared.mutex); destroy_expired(pool); while (1) { if (h2o_linklist_is_empty(&pool->_shared.sockets)) break; entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, link, pool->_shared.sockets.next); h2o_linklist_unlink(&entry->link); pthread_mutex_unlock(&pool->_shared.mutex); /* test if the connection is still alive */ char buf[1]; ssize_t rret = recv(entry->sockinfo.fd, buf, 1, MSG_PEEK); if (rret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { /* yes! return it */ h2o_socket_t *sock = h2o_socket_import(loop, &entry->sockinfo); free(entry); sock->on_close.cb = on_close; sock->on_close.data = pool; cb(sock, NULL, data); return; } /* connection is dead, report, close, and retry */ if (rret <= 0) { static long counter = 0; if (__sync_fetch_and_add(&counter, 1) == 0) fprintf(stderr, "[WARN] detected close by upstream before the expected timeout (see issue #679)\n"); } else { static long counter = 0; if (__sync_fetch_and_add(&counter, 1) == 0) fprintf(stderr, "[WARN] unexpectedly received data to a pooled socket (see issue #679)\n"); } destroy_detached(entry); pthread_mutex_lock(&pool->_shared.mutex); } pthread_mutex_unlock(&pool->_shared.mutex); /* FIXME repsect `capacity` */ __sync_add_and_fetch(&pool->_shared.count, 1); /* prepare request object */ h2o_socketpool_connect_request_t *req = h2o_mem_alloc(sizeof(*req)); *req = (h2o_socketpool_connect_request_t){data, cb, pool, loop}; if (_req != NULL) *_req = req; switch (pool->type) { case H2O_SOCKETPOOL_TYPE_NAMED: /* resolve the name, and connect */ req->getaddr_req = h2o_hostinfo_getaddr(getaddr_receiver, pool->peer.host, pool->peer.named_serv, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, AI_ADDRCONFIG | AI_NUMERICSERV, on_getaddr, req); break; case H2O_SOCKETPOOL_TYPE_SOCKADDR: /* connect (using sockaddr_in) */ start_connect(req, (void *)&pool->peer.sockaddr.bytes, pool->peer.sockaddr.len); break; } }
void h2o_socketpool_connect(h2o_socketpool_connect_request_t **_req, h2o_socketpool_t *pool, h2o_url_t *url, h2o_loop_t *loop, h2o_multithread_receiver_t *getaddr_receiver, h2o_socketpool_connect_cb cb, void *data) { struct pool_entry_t *entry = NULL; struct on_close_data_t *close_data; if (_req != NULL) *_req = NULL; size_t target = SIZE_MAX; h2o_linklist_t *sockets = NULL; /* fetch an entry and return it */ pthread_mutex_lock(&pool->_shared.mutex); destroy_expired(pool); /* TODO lookup outside this critical section */ if (is_global_pool(pool)) { target = lookup_target(pool, url); if (target == SIZE_MAX) { h2o_vector_reserve(NULL, &pool->targets, pool->targets.size + 1); pool->targets.entries[pool->targets.size++] = h2o_socketpool_create_target(url, NULL); target = pool->targets.size - 1; } sockets = &pool->targets.entries[target]->_shared.sockets; } else { sockets = &pool->_shared.sockets; } assert(pool->targets.size != 0); while (!h2o_linklist_is_empty(sockets)) { if (is_global_pool(pool)) { entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, target_link, sockets->next); } else { entry = H2O_STRUCT_FROM_MEMBER(struct pool_entry_t, all_link, sockets->next); } h2o_linklist_unlink(&entry->all_link); h2o_linklist_unlink(&entry->target_link); pthread_mutex_unlock(&pool->_shared.mutex); /* test if the connection is still alive */ char buf[1]; ssize_t rret = recv(entry->sockinfo.fd, buf, 1, MSG_PEEK); if (rret == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { /* yes! return it */ size_t entry_target = entry->target; h2o_socket_t *sock = h2o_socket_import(loop, &entry->sockinfo); free(entry); close_data = h2o_mem_alloc(sizeof(*close_data)); close_data->pool = pool; close_data->target = entry_target; sock->on_close.cb = on_close; sock->on_close.data = close_data; cb(sock, NULL, data, &pool->targets.entries[entry_target]->url); return; } /* connection is dead, report, close, and retry */ if (rret <= 0) { static long counter = 0; if (__sync_fetch_and_add(&counter, 1) == 0) fprintf(stderr, "[WARN] detected close by upstream before the expected timeout (see issue #679)\n"); } else { static long counter = 0; if (__sync_fetch_and_add(&counter, 1) == 0) fprintf(stderr, "[WARN] unexpectedly received data to a pooled socket (see issue #679)\n"); } destroy_detached(entry); pthread_mutex_lock(&pool->_shared.mutex); }