1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/socket.h>
29 #include "rtnl-internal.h"
30 #include "rtnl-util.h"
32 static int sd_rtnl_new(sd_rtnl **ret) {
35 assert_return(ret, -EINVAL);
37 rtnl = new0(sd_rtnl, 1);
41 rtnl->n_ref = REFCNT_INIT;
45 rtnl->sockaddr.nl.nl_family = AF_NETLINK;
47 rtnl->original_pid = getpid();
49 /* We guarantee that wqueue always has space for at least
51 rtnl->wqueue = new(sd_rtnl_message*, 1);
61 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
64 /* We don't support people creating an rtnl connection and
65 * keeping it around over a fork(). Let's complain. */
67 return rtnl->original_pid != getpid();
70 int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) {
71 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
75 r = sd_rtnl_new(&rtnl);
79 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
83 rtnl->sockaddr.nl.nl_groups = groups;
85 addrlen = sizeof(rtnl->sockaddr);
87 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
91 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
101 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
103 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
108 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
110 if (rtnl && REFCNT_DEC(rtnl->n_ref) <= 0) {
113 for (i = 0; i < rtnl->rqueue_size; i++)
114 sd_rtnl_message_unref(rtnl->rqueue[i]);
117 for (i = 0; i < rtnl->wqueue_size; i++)
118 sd_rtnl_message_unref(rtnl->wqueue[i]);
122 close_nointr_nofail(rtnl->fd);
130 int sd_rtnl_send(sd_rtnl *nl,
131 sd_rtnl_message *message,
135 assert_return(nl, -EINVAL);
136 assert_return(!rtnl_pid_changed(nl), -ECHILD);
137 assert_return(message, -EINVAL);
139 r = message_seal(nl, message);
143 if (nl->wqueue_size <= 0) {
145 r = socket_write_message(nl, message);
149 /* nothing was sent, so let's put it on
151 nl->wqueue[0] = sd_rtnl_message_ref(message);
157 /* append to queue */
158 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
161 q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
166 q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
170 *serial = message_get_serial(message);
175 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
176 sd_rtnl_message *z = NULL;
182 if (rtnl->rqueue_size > 0) {
183 /* Dispatch a queued message */
185 *message = rtnl->rqueue[0];
186 rtnl->rqueue_size --;
187 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
192 /* Try to read a new message */
193 r = socket_read_message(rtnl, &z);
204 static int dispatch_wqueue(sd_rtnl *rtnl) {
209 while (rtnl->wqueue_size > 0) {
210 r = socket_write_message(rtnl, rtnl->wqueue[0]);
214 /* Didn't do anything this time */
217 /* see equivalent in sd-bus.c */
218 sd_rtnl_message_unref(rtnl->wqueue[0]);
219 rtnl->wqueue_size --;
220 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
229 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
230 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
233 r = dispatch_wqueue(rtnl);
237 r = dispatch_rqueue(rtnl, &m);
258 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
261 assert_return(rtnl, -EINVAL);
262 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
263 assert_return(!rtnl->processing, -EBUSY);
265 rtnl->processing = true;
266 r = process_running(rtnl, ret);
267 rtnl->processing = false;
272 static usec_t calc_elapse(uint64_t usec) {
273 if (usec == (uint64_t) -1)
277 usec = RTNL_DEFAULT_TIMEOUT;
279 return now(CLOCK_MONOTONIC) + usec;
282 static int rtnl_poll(sd_rtnl *nl, uint64_t timeout_usec) {
283 struct pollfd p[1] = {};
290 p[0].events = POLLIN;
292 r = ppoll(p, 1, timeout_usec == (uint64_t) -1 ? NULL :
293 timespec_store(&ts, timeout_usec), NULL);
297 return r > 0 ? 1 : 0;
300 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
301 assert_return(nl, -EINVAL);
302 assert_return(!rtnl_pid_changed(nl), -ECHILD);
304 if (nl->rqueue_size > 0)
307 return rtnl_poll(nl, timeout_usec);
310 int sd_rtnl_call(sd_rtnl *nl,
311 sd_rtnl_message *message,
313 sd_rtnl_message **ret) {
319 assert_return(nl, -EINVAL);
320 assert_return(!rtnl_pid_changed(nl), -ECHILD);
321 assert_return(message, -EINVAL);
323 r = sd_rtnl_send(nl, message, &serial);
327 timeout = calc_elapse(usec);
331 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
336 if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
339 /* Make sure there's room for queueing this
340 * locally, before we read the message */
342 q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
350 r = socket_read_message(nl, &incoming);
354 uint32_t received_serial = message_get_serial(incoming);
356 if (received_serial == serial) {
357 r = message_get_errno(incoming);
369 /* Room was allocated on the queue above */
370 nl->rqueue[nl->rqueue_size ++] = incoming;
374 /* Try to read more, right away */
383 n = now(CLOCK_MONOTONIC);
389 left = (uint64_t) -1;
391 r = rtnl_poll(nl, left);
395 r = dispatch_wqueue(nl);