static void try_connect(h2o_socketpool_connect_request_t *req) { h2o_socketpool_target_t *target; req->remaining_try_count--; if (req->lb.tried != NULL) { if (req->pool->targets.size > 1) { req->selected_target = req->pool->balancer->callbacks->select_(req->pool->balancer, &req->pool->targets, req->lb.tried); assert(!req->lb.tried[req->selected_target]); req->lb.tried[req->selected_target] = 1; __sync_add_and_fetch(&req->pool->targets.entries[req->selected_target]->_shared.leased_count, 1); } else { req->selected_target = 0; } } target = req->pool->targets.entries[req->selected_target]; switch (target->type) { case H2O_SOCKETPOOL_TYPE_NAMED: /* resolve the name, and connect */ req->getaddr_req = h2o_hostinfo_getaddr(req->getaddr_receiver, target->url.host, target->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 *)&target->peer.sockaddr.bytes, target->peer.sockaddr.len); break; } }
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; } }