~ When file descriptors are exhausted, we might be better to try to * free an existing connection, rather than ignoring new ones. */
| 585 | /*~ When file descriptors are exhausted, we might be better to try to |
| 586 | * free an existing connection, rather than ignoring new ones. */ |
| 587 | void close_random_connection(struct daemon *daemon) |
| 588 | { |
| 589 | struct peer *peer, *best_peer = NULL; |
| 590 | size_t best_peer_score = PEER_SCORE_MAX + 1; |
| 591 | struct peer_htable_iter it; |
| 592 | struct connecting *c; |
| 593 | struct connecting_htable_iter cit; |
| 594 | bool closed_connect_attempt = false; |
| 595 | |
| 596 | /* First, close all transient connection attempts in-flight */ |
| 597 | for (c = connecting_htable_first(daemon->connecting, &cit); |
| 598 | c; |
| 599 | c = connecting_htable_next(daemon->connecting, &cit)) { |
| 600 | if (important_id_htable_get(daemon->important_ids, &c->id)) |
| 601 | continue; |
| 602 | |
| 603 | /* This could be the one caller is trying right now */ |
| 604 | if (!c->conn) |
| 605 | continue; |
| 606 | |
| 607 | status_debug("due to stress, closing transient connect attempt to %s", |
| 608 | fmt_node_id(tmpctx, &c->id)); |
| 609 | /* This tells destructor why it was closed */ |
| 610 | errno = EMFILE; |
| 611 | tal_free(c); |
| 612 | closed_connect_attempt = true; |
| 613 | } |
| 614 | |
| 615 | /* Prefer ones with no subds (just chatting), or failing that, |
| 616 | * ones we didn't deliberately connect to. */ |
| 617 | peer = peer_htable_pick(daemon->peers, pseudorand_u64(), &it); |
| 618 | |
| 619 | for (size_t i = 0; i < peer_htable_count(daemon->peers); i++) { |
| 620 | size_t score = peer_score(daemon, &peer->id, peer->subds); |
| 621 | if (score < best_peer_score) { |
| 622 | best_peer = peer; |
| 623 | best_peer_score = score; |
| 624 | /* Don't continue if we can't improve! */ |
| 625 | if (best_peer_score == 0) |
| 626 | break; |
| 627 | } |
| 628 | peer = peer_htable_next(daemon->peers, &it); |
| 629 | if (!peer) |
| 630 | peer = peer_htable_first(daemon->peers, &it); |
| 631 | } |
| 632 | |
| 633 | if (!best_peer) |
| 634 | return; |
| 635 | |
| 636 | /* Don't close active peer if we closed an attempt */ |
| 637 | if (closed_connect_attempt |
| 638 | && best_peer_score > 1) |
| 639 | return; |
| 640 | |
| 641 | status_debug("due to stress, randomly closing peer %s (score %zu)", |
| 642 | fmt_node_id(tmpctx, &best_peer->id), best_peer_score); |
| 643 | io_close(best_peer->to_peer); |
| 644 | } |
no test coverage detected