• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 15057632786

15 May 2025 09:01PM UTC coverage: 72.267% (+0.02%) from 72.244%
15057632786

push

github

bluca
man: document how to hook stuff into system wakeup

Fixes: #6364

298523 of 413084 relevant lines covered (72.27%)

738132.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.88
/src/resolve/resolved-socket-graveyard.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include "alloc-util.h"
4
#include "resolved-manager.h"
5
#include "resolved-socket-graveyard.h"
6

7
#define SOCKET_GRAVEYARD_USEC (5 * USEC_PER_SEC)
8
#define SOCKET_GRAVEYARD_MAX 100
9

10
/* This implements a socket "graveyard" for UDP sockets. If a socket fd is added to the graveyard it is kept
11
 * open for a couple of more seconds, expecting one reply. Once the reply is received the fd is closed
12
 * immediately, or if none is received it is closed after the timeout. Why all this? So that if we contact a
13
 * DNS server, and it doesn't reply instantly, and we lose interest in the response and thus close the fd, we
14
 * don't end up sending back an ICMP error once the server responds but we aren't listening anymore. (See
15
 * https://github.com/systemd/systemd/issues/17421 for further information.)
16
 *
17
 * Note that we don't allocate any timer event source to clear up the graveyard once the socket's timeout is
18
 * reached. Instead we operate lazily: we close old entries when adding a new fd to the graveyard, or
19
 * whenever any code runs manager_socket_graveyard_process() — which the DNS transaction code does right
20
 * before allocating a new UDP socket. */
21

22
static SocketGraveyard* socket_graveyard_free(SocketGraveyard *g) {
174✔
23
        if (!g)
174✔
24
                return NULL;
25

26
        if (g->manager) {
174✔
27
                assert(g->manager->n_socket_graveyard > 0);
174✔
28
                g->manager->n_socket_graveyard--;
174✔
29

30
                if (g->manager->socket_graveyard_oldest == g)
174✔
31
                        g->manager->socket_graveyard_oldest = g->graveyard_prev;
163✔
32

33
                LIST_REMOVE(graveyard, g->manager->socket_graveyard, g);
174✔
34

35
                assert((g->manager->n_socket_graveyard > 0) == !!g->manager->socket_graveyard);
174✔
36
                assert((g->manager->n_socket_graveyard > 0) == !!g->manager->socket_graveyard_oldest);
174✔
37
        }
38

39
        if (g->io_event_source) {
174✔
40
                log_debug("Closing graveyard socket fd %i", sd_event_source_get_io_fd(g->io_event_source));
174✔
41
                sd_event_source_disable_unref(g->io_event_source);
174✔
42
        }
43

44
        return mfree(g);
174✔
45
}
46

47
DEFINE_TRIVIAL_CLEANUP_FUNC(SocketGraveyard*, socket_graveyard_free);
175✔
48

49
void manager_socket_graveyard_process(Manager *m) {
11,031✔
50
        usec_t n = USEC_INFINITY;
11,031✔
51

52
        assert(m);
11,031✔
53

54
        while (m->socket_graveyard_oldest) {
11,189✔
55
                SocketGraveyard *g = m->socket_graveyard_oldest;
2,399✔
56

57
                if (n == USEC_INFINITY)
2,399✔
58
                        assert_se(sd_event_now(m->event, CLOCK_BOOTTIME, &n) >= 0);
2,301✔
59

60
                if (g->deadline > n)
2,399✔
61
                        break;
62

63
                socket_graveyard_free(g);
158✔
64
        }
65
}
11,031✔
66

67
void manager_socket_graveyard_clear(Manager *m) {
165✔
68
        assert(m);
165✔
69

70
        while (m->socket_graveyard)
181✔
71
                socket_graveyard_free(m->socket_graveyard);
16✔
72
}
165✔
73

74
static int on_io_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
×
75
        SocketGraveyard *g = ASSERT_PTR(userdata);
×
76

77
        /* An IO event happened on the graveyard fd. We don't actually care which event that is, and we don't
78
         * read any incoming packet off the socket. We just close the fd, that's enough to not trigger the
79
         * ICMP unreachable port event */
80

81
        socket_graveyard_free(g);
×
82
        return 0;
×
83
}
84

85
static void manager_socket_graveyard_make_room(Manager *m) {
175✔
86
        assert(m);
175✔
87

88
        while (m->n_socket_graveyard >= SOCKET_GRAVEYARD_MAX)
175✔
89
                socket_graveyard_free(m->socket_graveyard_oldest);
×
90
}
175✔
91

92
int manager_add_socket_to_graveyard(Manager *m, int fd) {
175✔
93
        _cleanup_(socket_graveyard_freep) SocketGraveyard *g = NULL;
175✔
94
        int r;
175✔
95

96
        assert(m);
175✔
97
        assert(fd >= 0);
175✔
98

99
        manager_socket_graveyard_process(m);
175✔
100
        manager_socket_graveyard_make_room(m);
175✔
101

102
        g = new(SocketGraveyard, 1);
175✔
103
        if (!g)
175✔
104
                return log_oom();
×
105

106
        *g = (SocketGraveyard) {
175✔
107
                .manager = m,
108
        };
109

110
        LIST_PREPEND(graveyard, m->socket_graveyard, g);
175✔
111
        if (!m->socket_graveyard_oldest)
175✔
112
                m->socket_graveyard_oldest = g;
66✔
113

114
        m->n_socket_graveyard++;
175✔
115

116
        assert_se(sd_event_now(m->event, CLOCK_BOOTTIME, &g->deadline) >= 0);
175✔
117
        g->deadline += SOCKET_GRAVEYARD_USEC;
175✔
118

119
        r = sd_event_add_io(m->event, &g->io_event_source, fd, EPOLLIN, on_io_event, g);
175✔
120
        if (r < 0)
175✔
121
                return log_error_errno(r, "Failed to create graveyard IO source: %m");
×
122

123
        r = sd_event_source_set_io_fd_own(g->io_event_source, true);
175✔
124
        if (r < 0)
175✔
125
                return log_error_errno(r, "Failed to enable graveyard IO source fd ownership: %m");
×
126

127
        (void) sd_event_source_set_description(g->io_event_source, "graveyard");
175✔
128

129
        log_debug("Added socket %i to graveyard", fd);
175✔
130

131
        TAKE_PTR(g);
175✔
132
        return 0;
175✔
133
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc