chiark / gitweb /
sd-rtnl: don't fail event handler when callback fails
[elogind.git] / src / libsystemd / sd-rtnl / sd-rtnl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <poll.h>
24
25 #include "missing.h"
26 #include "macro.h"
27 #include "util.h"
28 #include "hashmap.h"
29
30 #include "sd-rtnl.h"
31 #include "rtnl-internal.h"
32 #include "rtnl-util.h"
33
34 static int sd_rtnl_new(sd_rtnl **ret) {
35         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
36
37         assert_return(ret, -EINVAL);
38
39         rtnl = new0(sd_rtnl, 1);
40         if (!rtnl)
41                 return -ENOMEM;
42
43         rtnl->n_ref = REFCNT_INIT;
44
45         rtnl->fd = -1;
46
47         rtnl->sockaddr.nl.nl_family = AF_NETLINK;
48
49         rtnl->original_pid = getpid();
50
51         LIST_HEAD_INIT(rtnl->match_callbacks);
52
53         /* We guarantee that wqueue always has space for at least
54          * one entry */
55         if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
56                 return -ENOMEM;
57
58         /* We guarantee that the read buffer has at least space for
59          * a message header */
60         if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
61                             sizeof(struct nlmsghdr), sizeof(uint8_t)))
62                 return -ENOMEM;
63
64         *ret = rtnl;
65         rtnl = NULL;
66
67         return 0;
68 }
69
70 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
71         assert(rtnl);
72
73         /* We don't support people creating an rtnl connection and
74          * keeping it around over a fork(). Let's complain. */
75
76         return rtnl->original_pid != getpid();
77 }
78
79 static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) {
80         uint32_t groups = 0;
81         unsigned i;
82
83         for (i = 0; i < n_groups; i++) {
84                 unsigned group;
85
86                 group = va_arg(ap, unsigned);
87                 assert_return(group < 32, -EINVAL);
88
89                 groups |= group ? (1 << (group - 1)) : 0;
90         }
91
92         *_groups = groups;
93
94         return 0;
95 }
96
97 static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) {
98         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
99         socklen_t addrlen;
100         int r, one = 1;
101
102         assert_return(ret, -EINVAL);
103         assert_return(fd >= 0, -EINVAL);
104
105         r = sd_rtnl_new(&rtnl);
106         if (r < 0)
107                 return r;
108
109         r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
110         if (r < 0)
111                 return -errno;
112
113         r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
114         if (r < 0)
115                 return -errno;
116
117         r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
118         if (r < 0)
119                 return r;
120
121         addrlen = sizeof(rtnl->sockaddr);
122
123         r = bind(fd, &rtnl->sockaddr.sa, addrlen);
124         if (r < 0)
125                 return -errno;
126
127         r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
128         if (r < 0)
129                 return r;
130
131         rtnl->fd = fd;
132
133         *ret = rtnl;
134         rtnl = NULL;
135
136         return 0;
137 }
138
139 int sd_rtnl_open_fd(sd_rtnl **ret, int fd, unsigned n_groups, ...) {
140         va_list ap;
141         int r;
142
143         va_start(ap, n_groups);
144         r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
145         va_end(ap);
146
147         return r;
148 }
149
150 int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
151         va_list ap;
152         int fd, r;
153
154         fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
155         if (fd < 0)
156                 return -errno;
157
158         va_start(ap, n_groups);
159         r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
160         va_end(ap);
161
162         if (r < 0) {
163                 safe_close(fd);
164                 return r;
165         }
166
167         return 0;
168 }
169
170 int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
171         return fd_inc_rcvbuf(rtnl->fd, size);
172 }
173
174 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
175         assert_return(rtnl, NULL);
176         assert_return(!rtnl_pid_changed(rtnl), NULL);
177
178         if (rtnl)
179                 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
180
181         return rtnl;
182 }
183
184 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
185         if (!rtnl)
186                 return NULL;
187
188         assert_return(!rtnl_pid_changed(rtnl), NULL);
189
190         if (REFCNT_DEC(rtnl->n_ref) == 0) {
191                 struct match_callback *f;
192                 unsigned i;
193
194                 for (i = 0; i < rtnl->rqueue_size; i++)
195                         sd_rtnl_message_unref(rtnl->rqueue[i]);
196                 free(rtnl->rqueue);
197
198                 for (i = 0; i < rtnl->rqueue_partial_size; i++)
199                         sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
200                 free(rtnl->rqueue_partial);
201
202                 for (i = 0; i < rtnl->wqueue_size; i++)
203                         sd_rtnl_message_unref(rtnl->wqueue[i]);
204                 free(rtnl->wqueue);
205
206                 free(rtnl->rbuffer);
207
208                 hashmap_free_free(rtnl->reply_callbacks);
209                 prioq_free(rtnl->reply_callbacks_prioq);
210
211                 sd_event_source_unref(rtnl->io_event_source);
212                 sd_event_source_unref(rtnl->time_event_source);
213                 sd_event_source_unref(rtnl->exit_event_source);
214                 sd_event_unref(rtnl->event);
215
216                 while ((f = rtnl->match_callbacks)) {
217                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
218                         free(f);
219                 }
220
221                 safe_close(rtnl->fd);
222                 free(rtnl);
223         }
224
225         return NULL;
226 }
227
228 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
229         assert(rtnl);
230         assert(!rtnl_pid_changed(rtnl));
231         assert(m);
232         assert(m->hdr);
233
234         m->hdr->nlmsg_seq = rtnl->serial++;
235
236         rtnl_message_seal(m);
237
238         return;
239 }
240
241 int sd_rtnl_send(sd_rtnl *nl,
242                  sd_rtnl_message *message,
243                  uint32_t *serial) {
244         int r;
245
246         assert_return(nl, -EINVAL);
247         assert_return(!rtnl_pid_changed(nl), -ECHILD);
248         assert_return(message, -EINVAL);
249         assert_return(!message->sealed, -EPERM);
250
251         rtnl_seal_message(nl, message);
252
253         if (nl->wqueue_size <= 0) {
254                 /* send directly */
255                 r = socket_write_message(nl, message);
256                 if (r < 0)
257                         return r;
258                 else if (r == 0) {
259                         /* nothing was sent, so let's put it on
260                          * the queue */
261                         nl->wqueue[0] = sd_rtnl_message_ref(message);
262                         nl->wqueue_size = 1;
263                 }
264         } else {
265                 /* append to queue */
266                 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
267                         log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
268                         return -ENOBUFS;
269                 }
270
271                 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
272                         return -ENOMEM;
273
274                 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
275         }
276
277         if (serial)
278                 *serial = rtnl_message_get_serial(message);
279
280         return 1;
281 }
282
283 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
284         assert(rtnl);
285
286         if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
287                 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
288                 return -ENOBUFS;
289         }
290
291         if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
292                 return -ENOMEM;
293
294         return 0;
295 }
296
297 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
298         assert(rtnl);
299
300         if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
301                 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
302                 return -ENOBUFS;
303         }
304
305         if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
306                             rtnl->rqueue_partial_size + 1))
307                 return -ENOMEM;
308
309         return 0;
310 }
311
312 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
313         int r;
314
315         assert(rtnl);
316         assert(message);
317
318         if (rtnl->rqueue_size <= 0) {
319                 /* Try to read a new message */
320                 r = socket_read_message(rtnl);
321                 if (r <= 0)
322                         return r;
323         }
324
325         /* Dispatch a queued message */
326         *message = rtnl->rqueue[0];
327         rtnl->rqueue_size --;
328         memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
329
330         return 1;
331 }
332
333 static int dispatch_wqueue(sd_rtnl *rtnl) {
334         int r, ret = 0;
335
336         assert(rtnl);
337
338         while (rtnl->wqueue_size > 0) {
339                 r = socket_write_message(rtnl, rtnl->wqueue[0]);
340                 if (r < 0)
341                         return r;
342                 else if (r == 0)
343                         /* Didn't do anything this time */
344                         return ret;
345                 else {
346                         /* see equivalent in sd-bus.c */
347                         sd_rtnl_message_unref(rtnl->wqueue[0]);
348                         rtnl->wqueue_size --;
349                         memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
350
351                         ret = 1;
352                 }
353         }
354
355         return ret;
356 }
357
358 static int process_timeout(sd_rtnl *rtnl) {
359         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
360         struct reply_callback *c;
361         usec_t n;
362         int r;
363
364         assert(rtnl);
365
366         c = prioq_peek(rtnl->reply_callbacks_prioq);
367         if (!c)
368                 return 0;
369
370         n = now(CLOCK_MONOTONIC);
371         if (c->timeout > n)
372                 return 0;
373
374         r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
375         if (r < 0)
376                 return r;
377
378         assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
379         hashmap_remove(rtnl->reply_callbacks, &c->serial);
380
381         r = c->callback(rtnl, m, c->userdata);
382         if (r < 0)
383                 log_debug_errno(r, "sd-rtnl: timedout callback failed: %m");
384
385         free(c);
386
387         return 1;
388 }
389
390 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
391         struct reply_callback *c;
392         uint64_t serial;
393         int r;
394
395         assert(rtnl);
396         assert(m);
397
398         if (sd_rtnl_message_is_broadcast(m))
399                 return 0;
400
401         serial = rtnl_message_get_serial(m);
402         c = hashmap_remove(rtnl->reply_callbacks, &serial);
403         if (!c)
404                 return 0;
405
406         if (c->timeout != 0)
407                 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
408
409         r = c->callback(rtnl, m, c->userdata);
410         if (r < 0)
411                 log_debug_errno(r, "sd-rtnl: callback failed: %m");
412
413         free(c);
414
415         return 1;
416 }
417
418 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
419         struct match_callback *c;
420         uint16_t type;
421         int r;
422
423         assert(rtnl);
424         assert(m);
425
426         r = sd_rtnl_message_get_type(m, &type);
427         if (r < 0)
428                 return r;
429
430         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
431                 if (type == c->type) {
432                         r = c->callback(rtnl, m, c->userdata);
433                         if (r != 0) {
434                                 if (r < 0)
435                                         log_debug_errno(r, "sd-rtnl: match callback failed: %m");
436
437                                 break;
438                         }
439                 }
440         }
441
442         return 1;
443 }
444
445 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
446         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
447         int r;
448
449         assert(rtnl);
450
451         r = process_timeout(rtnl);
452         if (r != 0)
453                 goto null_message;
454
455         r = dispatch_wqueue(rtnl);
456         if (r != 0)
457                 goto null_message;
458
459         r = dispatch_rqueue(rtnl, &m);
460         if (r < 0)
461                 return r;
462         if (!m)
463                 goto null_message;
464
465         r = process_reply(rtnl, m);
466         if (r != 0)
467                 goto null_message;
468
469         r = process_match(rtnl, m);
470         if (r != 0)
471                 goto null_message;
472
473         if (ret) {
474                 *ret = m;
475                 m = NULL;
476
477                 return 1;
478         }
479
480         return 1;
481
482 null_message:
483         if (r >= 0 && ret)
484                 *ret = NULL;
485
486         return r;
487 }
488
489 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
490         RTNL_DONT_DESTROY(rtnl);
491         int r;
492
493         assert_return(rtnl, -EINVAL);
494         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
495         assert_return(!rtnl->processing, -EBUSY);
496
497         rtnl->processing = true;
498         r = process_running(rtnl, ret);
499         rtnl->processing = false;
500
501         return r;
502 }
503
504 static usec_t calc_elapse(uint64_t usec) {
505         if (usec == (uint64_t) -1)
506                 return 0;
507
508         if (usec == 0)
509                 usec = RTNL_DEFAULT_TIMEOUT;
510
511         return now(CLOCK_MONOTONIC) + usec;
512 }
513
514 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
515         struct pollfd p[1] = {};
516         struct timespec ts;
517         usec_t m = USEC_INFINITY;
518         int r, e;
519
520         assert(rtnl);
521
522         e = sd_rtnl_get_events(rtnl);
523         if (e < 0)
524                 return e;
525
526         if (need_more)
527                 /* Caller wants more data, and doesn't care about
528                  * what's been read or any other timeouts. */
529                 e |= POLLIN;
530         else {
531                 usec_t until;
532                 /* Caller wants to process if there is something to
533                  * process, but doesn't care otherwise */
534
535                 r = sd_rtnl_get_timeout(rtnl, &until);
536                 if (r < 0)
537                         return r;
538                 if (r > 0) {
539                         usec_t nw;
540                         nw = now(CLOCK_MONOTONIC);
541                         m = until > nw ? until - nw : 0;
542                 }
543         }
544
545         if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
546                 m = timeout_usec;
547
548         p[0].fd = rtnl->fd;
549         p[0].events = e;
550
551         r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
552         if (r < 0)
553                 return -errno;
554
555         return r > 0 ? 1 : 0;
556 }
557
558 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
559         assert_return(nl, -EINVAL);
560         assert_return(!rtnl_pid_changed(nl), -ECHILD);
561
562         if (nl->rqueue_size > 0)
563                 return 0;
564
565         return rtnl_poll(nl, false, timeout_usec);
566 }
567
568 static int timeout_compare(const void *a, const void *b) {
569         const struct reply_callback *x = a, *y = b;
570
571         if (x->timeout != 0 && y->timeout == 0)
572                 return -1;
573
574         if (x->timeout == 0 && y->timeout != 0)
575                 return 1;
576
577         if (x->timeout < y->timeout)
578                 return -1;
579
580         if (x->timeout > y->timeout)
581                 return 1;
582
583         return 0;
584 }
585
586 int sd_rtnl_call_async(sd_rtnl *nl,
587                        sd_rtnl_message *m,
588                        sd_rtnl_message_handler_t callback,
589                        void *userdata,
590                        uint64_t usec,
591                        uint32_t *serial) {
592         struct reply_callback *c;
593         uint32_t s;
594         int r, k;
595
596         assert_return(nl, -EINVAL);
597         assert_return(m, -EINVAL);
598         assert_return(callback, -EINVAL);
599         assert_return(!rtnl_pid_changed(nl), -ECHILD);
600
601         r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
602         if (r < 0)
603                 return r;
604
605         if (usec != (uint64_t) -1) {
606                 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
607                 if (r < 0)
608                         return r;
609         }
610
611         c = new0(struct reply_callback, 1);
612         if (!c)
613                 return -ENOMEM;
614
615         c->callback = callback;
616         c->userdata = userdata;
617         c->timeout = calc_elapse(usec);
618
619         k = sd_rtnl_send(nl, m, &s);
620         if (k < 0) {
621                 free(c);
622                 return k;
623         }
624
625         c->serial = s;
626
627         r = hashmap_put(nl->reply_callbacks, &c->serial, c);
628         if (r < 0) {
629                 free(c);
630                 return r;
631         }
632
633         if (c->timeout != 0) {
634                 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
635                 if (r > 0) {
636                         c->timeout = 0;
637                         sd_rtnl_call_async_cancel(nl, c->serial);
638                         return r;
639                 }
640         }
641
642         if (serial)
643                 *serial = s;
644
645         return k;
646 }
647
648 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
649         struct reply_callback *c;
650         uint64_t s = serial;
651
652         assert_return(nl, -EINVAL);
653         assert_return(serial != 0, -EINVAL);
654         assert_return(!rtnl_pid_changed(nl), -ECHILD);
655
656         c = hashmap_remove(nl->reply_callbacks, &s);
657         if (!c)
658                 return 0;
659
660         if (c->timeout != 0)
661                 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
662
663         free(c);
664         return 1;
665 }
666
667 int sd_rtnl_call(sd_rtnl *rtnl,
668                 sd_rtnl_message *message,
669                 uint64_t usec,
670                 sd_rtnl_message **ret) {
671         usec_t timeout;
672         uint32_t serial;
673         unsigned i = 0;
674         int r;
675
676         assert_return(rtnl, -EINVAL);
677         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
678         assert_return(message, -EINVAL);
679
680         r = sd_rtnl_send(rtnl, message, &serial);
681         if (r < 0)
682                 return r;
683
684         timeout = calc_elapse(usec);
685
686         for (;;) {
687                 usec_t left;
688
689                 while (i < rtnl->rqueue_size) {
690                         sd_rtnl_message *incoming;
691                         uint32_t received_serial;
692
693                         incoming = rtnl->rqueue[i];
694                         received_serial = rtnl_message_get_serial(incoming);
695
696                         if (received_serial == serial) {
697                                 /* found a match, remove from rqueue and return it */
698                                 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
699                                         sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
700                                 rtnl->rqueue_size--;
701
702                                 r = sd_rtnl_message_get_errno(incoming);
703                                 if (r < 0) {
704                                         sd_rtnl_message_unref(incoming);
705                                         return r;
706                                 }
707
708                                 if (ret) {
709                                         *ret = incoming;
710                                 } else
711                                         sd_rtnl_message_unref(incoming);
712
713                                 return 1;
714                         }
715
716                         /* Try to read more, right away */
717                         i ++;
718                 }
719
720                 r = socket_read_message(rtnl);
721                 if (r < 0)
722                         return r;
723                 if (r > 0)
724                         /* received message, so try to process straight away */
725                         continue;
726
727                 if (timeout > 0) {
728                         usec_t n;
729
730                         n = now(CLOCK_MONOTONIC);
731                         if (n >= timeout)
732                                 return -ETIMEDOUT;
733
734                         left = timeout - n;
735                 } else
736                         left = (uint64_t) -1;
737
738                 r = rtnl_poll(rtnl, true, left);
739                 if (r < 0)
740                         return r;
741                 else if (r == 0)
742                         return -ETIMEDOUT;
743
744                 r = dispatch_wqueue(rtnl);
745                 if (r < 0)
746                         return r;
747         }
748 }
749
750 int sd_rtnl_flush(sd_rtnl *rtnl) {
751         int r;
752
753         assert_return(rtnl, -EINVAL);
754         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
755
756         if (rtnl->wqueue_size <= 0)
757                 return 0;
758
759         for (;;) {
760                 r = dispatch_wqueue(rtnl);
761                 if (r < 0)
762                         return r;
763
764                 if (rtnl->wqueue_size <= 0)
765                         return 0;
766
767                 r = rtnl_poll(rtnl, false, (uint64_t) -1);
768                 if (r < 0)
769                         return r;
770         }
771 }
772
773 int sd_rtnl_get_events(sd_rtnl *rtnl) {
774         int flags = 0;
775
776         assert_return(rtnl, -EINVAL);
777         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
778
779         if (rtnl->rqueue_size <= 0)
780                 flags |= POLLIN;
781         if (rtnl->wqueue_size > 0)
782                 flags |= POLLOUT;
783
784         return flags;
785 }
786
787 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
788         struct reply_callback *c;
789
790         assert_return(rtnl, -EINVAL);
791         assert_return(timeout_usec, -EINVAL);
792         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
793
794         if (rtnl->rqueue_size > 0) {
795                 *timeout_usec = 0;
796                 return 1;
797         }
798
799         c = prioq_peek(rtnl->reply_callbacks_prioq);
800         if (!c) {
801                 *timeout_usec = (uint64_t) -1;
802                 return 0;
803         }
804
805         *timeout_usec = c->timeout;
806
807         return 1;
808 }
809
810 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
811         sd_rtnl *rtnl = userdata;
812         int r;
813
814         assert(rtnl);
815
816         r = sd_rtnl_process(rtnl, NULL);
817         if (r < 0)
818                 return r;
819
820         return 1;
821 }
822
823 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
824         sd_rtnl *rtnl = userdata;
825         int r;
826
827         assert(rtnl);
828
829         r = sd_rtnl_process(rtnl, NULL);
830         if (r < 0)
831                 return r;
832
833         return 1;
834 }
835
836 static int prepare_callback(sd_event_source *s, void *userdata) {
837         sd_rtnl *rtnl = userdata;
838         int r, e;
839         usec_t until;
840
841         assert(s);
842         assert(rtnl);
843
844         e = sd_rtnl_get_events(rtnl);
845         if (e < 0)
846                 return e;
847
848         r = sd_event_source_set_io_events(rtnl->io_event_source, e);
849         if (r < 0)
850                 return r;
851
852         r = sd_rtnl_get_timeout(rtnl, &until);
853         if (r < 0)
854                 return r;
855         if (r > 0) {
856                 int j;
857
858                 j = sd_event_source_set_time(rtnl->time_event_source, until);
859                 if (j < 0)
860                         return j;
861         }
862
863         r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
864         if (r < 0)
865                 return r;
866
867         return 1;
868 }
869
870 static int exit_callback(sd_event_source *event, void *userdata) {
871         sd_rtnl *rtnl = userdata;
872
873         assert(event);
874
875         sd_rtnl_flush(rtnl);
876
877         return 1;
878 }
879
880 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
881         int r;
882
883         assert_return(rtnl, -EINVAL);
884         assert_return(!rtnl->event, -EBUSY);
885
886         assert(!rtnl->io_event_source);
887         assert(!rtnl->time_event_source);
888
889         if (event)
890                 rtnl->event = sd_event_ref(event);
891         else {
892                 r = sd_event_default(&rtnl->event);
893                 if (r < 0)
894                         return r;
895         }
896
897         r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
898         if (r < 0)
899                 goto fail;
900
901         r = sd_event_source_set_priority(rtnl->io_event_source, priority);
902         if (r < 0)
903                 goto fail;
904
905         r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
906         if (r < 0)
907                 goto fail;
908
909         r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
910         if (r < 0)
911                 goto fail;
912
913         r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
914         if (r < 0)
915                 goto fail;
916
917         r = sd_event_source_set_priority(rtnl->time_event_source, priority);
918         if (r < 0)
919                 goto fail;
920
921         r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
922         if (r < 0)
923                 goto fail;
924
925         r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
926         if (r < 0)
927                 goto fail;
928
929         r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
930         if (r < 0)
931                 goto fail;
932
933         return 0;
934
935 fail:
936         sd_rtnl_detach_event(rtnl);
937         return r;
938 }
939
940 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
941         assert_return(rtnl, -EINVAL);
942         assert_return(rtnl->event, -ENXIO);
943
944         if (rtnl->io_event_source)
945                 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
946
947         if (rtnl->time_event_source)
948                 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
949
950         if (rtnl->exit_event_source)
951                 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
952
953         if (rtnl->event)
954                 rtnl->event = sd_event_unref(rtnl->event);
955
956         return 0;
957 }
958
959 int sd_rtnl_add_match(sd_rtnl *rtnl,
960                       uint16_t type,
961                       sd_rtnl_message_handler_t callback,
962                       void *userdata) {
963         struct match_callback *c;
964
965         assert_return(rtnl, -EINVAL);
966         assert_return(callback, -EINVAL);
967         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
968         assert_return(rtnl_message_type_is_link(type) ||
969                       rtnl_message_type_is_addr(type) ||
970                       rtnl_message_type_is_route(type), -ENOTSUP);
971
972         c = new0(struct match_callback, 1);
973         if (!c)
974                 return -ENOMEM;
975
976         c->callback = callback;
977         c->type = type;
978         c->userdata = userdata;
979
980         LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
981
982         return 0;
983 }
984
985 int sd_rtnl_remove_match(sd_rtnl *rtnl,
986                          uint16_t type,
987                          sd_rtnl_message_handler_t callback,
988                          void *userdata) {
989         struct match_callback *c;
990
991         assert_return(rtnl, -EINVAL);
992         assert_return(callback, -EINVAL);
993         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
994
995         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
996                 if (c->callback == callback && c->type == type && c->userdata == userdata) {
997                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
998                         free(c);
999
1000                         return 1;
1001                 }
1002
1003         return 0;
1004 }