static int tcp_wait_for_events(tcp_context_t *tcp) { /* Wait for events. */ fdset_t *set = &tcp->set; int nfds = poll(set->pfd, set->n, TCP_SWEEP_INTERVAL * 1000); /* Mark the time of last poll call. */ time_now(&tcp->last_poll_time); bool is_throttled = (tcp->last_poll_time.tv_sec < tcp->throttle_end.tv_sec); if (!is_throttled) { /* Configuration limit, infer maximal pool size. */ rcu_read_lock(); conf_val_t *val = &conf()->cache.srv_max_tcp_clients; unsigned max_per_set = MAX(conf_int(val) / conf_tcp_threads(conf()), 1); rcu_read_unlock(); /* Subtract master sockets check limits. */ is_throttled = (set->n - tcp->client_threshold) >= max_per_set; } /* Process events. */ unsigned i = 0; while (nfds > 0 && i < set->n) { bool should_close = false; int fd = set->pfd[i].fd; if (set->pfd[i].revents & (POLLERR|POLLHUP|POLLNVAL)) { should_close = (i >= tcp->client_threshold); --nfds; } else if (set->pfd[i].revents & (POLLIN)) { /* Master sockets */ if (i < tcp->client_threshold) { if (!is_throttled && tcp_event_accept(tcp, i) == KNOT_EBUSY) { time_now(&tcp->throttle_end); tcp->throttle_end.tv_sec += tcp_throttle(); } /* Client sockets */ } else { if (tcp_event_serve(tcp, i) != KNOT_EOK) { should_close = true; } } --nfds; } /* Evaluate */ if (should_close) { fdset_remove(set, i); close(fd); } else { ++i; } } return nfds; }
int tcp_accept(int fd) { /* Accept incoming connection. */ int incoming = accept(fd, 0, 0); /* Evaluate connection. */ if (incoming < 0) { int en = errno; if (en != EINTR && en != EAGAIN) { log_error("cannot accept connection (%d)", errno); if (en == EMFILE || en == ENFILE || en == ENOBUFS || en == ENOMEM) { int throttle = tcp_throttle(); log_error("throttling TCP connection pool for " "%d seconds, too many allocated " "resources", throttle); sleep(throttle); } } } else { dbg_net("tcp: accepted connection fd=%d\n", incoming); /* Set recv() timeout. */ #ifdef SO_RCVTIMEO struct timeval tv; rcu_read_lock(); tv.tv_sec = conf()->max_conn_idle; rcu_read_unlock(); tv.tv_usec = 0; if (setsockopt(incoming, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { log_warning("cannot set up TCP connection watchdog " "timer, fd %d", incoming); } #endif } return incoming; }